cbfstool: expose rmodule logic

In order to allow cbfstool to add XIP romstage on x86 without
doing the 'cbfstool locate', relink, then 'cbfstool add' dance
expose the core logic and of rmodule including proving an optional
filter. The filter will be used for ignoring relocations to the
.car.global region.

BUG=chrome-os-partner:44827
BRANCH=None
TEST=Built rambi.

Change-Id: I192ae2e2f2e727d3183d32fd3eef8b64aacd92f4
Signed-off-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/11598
Tested-by: build bot (Jenkins)
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
diff --git a/util/cbfstool/rmodule.c b/util/cbfstool/rmodule.c
index 03828f7..46c9384 100644
--- a/util/cbfstool/rmodule.c
+++ b/util/cbfstool/rmodule.c
@@ -24,39 +24,6 @@
 #include "rmodule.h"
 #include "../../src/include/rmodule-defs.h"
 
-struct rmod_context;
-
-struct arch_ops {
-	int arch;
-	/* Determine if relocation is a valid type for the architecture. */
-	int (*valid_type)(Elf64_Rela *rel);
-	/* Determine if relocation should be emitted. */
-	int (*should_emit)(Elf64_Rela *rel);
-};
-
-struct rmod_context {
-	/* Ops to process relocations. */
-	struct arch_ops *ops;
-
-	/* endian conversion ops */
-	struct xdr *xdr;
-
-	/* Parsed ELF sturcture. */
-	struct parsed_elf pelf;
-	/* Program segment. */
-	Elf64_Phdr *phdr;
-
-	/* Collection of relocation addresses fixup in the module. */
-	Elf64_Xword nrelocs;
-	Elf64_Addr *emitted_relocs;
-
-	/* The following fields are addresses within the linked program.  */
-	Elf64_Addr parameters_begin;
-	Elf64_Addr parameters_end;
-	Elf64_Addr bss_begin;
-	Elf64_Addr bss_end;
-};
-
 /*
  * Architecture specific support operations.
  */
@@ -130,7 +97,7 @@
 	return (type == R_AARCH64_ABS64);
 }
 
-static struct arch_ops reloc_ops[] = {
+static const struct arch_ops reloc_ops[] = {
 	{
 		.arch = EM_386,
 		.valid_type = valid_reloc_386,
@@ -152,7 +119,8 @@
  * Relocation processing loops.
  */
 
-static int for_each_reloc(struct rmod_context *ctx, int do_emit)
+static int for_each_reloc(struct rmod_context *ctx, struct reloc_filter *f,
+				int do_emit)
 {
 	Elf64_Half i;
 	struct parsed_elf *pelf = &ctx->pelf;
@@ -173,6 +141,7 @@
 		nrelocs = shdr->sh_size / shdr->sh_entsize;
 
 		for (j = 0; j < nrelocs; j++) {
+			int filter_emit = 1;
 			Elf64_Rela *r = &relocs[j];
 
 			if (!ctx->ops->valid_type(r)) {
@@ -181,7 +150,15 @@
 				return -1;
 			}
 
-			if (ctx->ops->should_emit(r)) {
+			/* Allow the provided filter to have precedence. */
+			if (f != NULL) {
+				filter_emit = f->filter(f, r);
+
+				if (filter_emit < 0)
+					return filter_emit;
+			}
+
+			if (filter_emit && ctx->ops->should_emit(r)) {
 				int n = ctx->nrelocs;
 				if (do_emit)
 					ctx->emitted_relocs[n] = r->r_offset;
@@ -303,7 +280,8 @@
 	return 0;
 }
 
-static int collect_relocations(struct rmod_context *ctx)
+int rmodule_collect_relocations(struct rmod_context *ctx,
+				struct reloc_filter *f)
 {
 	Elf64_Xword nrelocs;
 
@@ -312,7 +290,7 @@
 	 * apply to the program. Count the number relocations. Then collect
 	 * them into the allocated buffer.
 	 */
-	if (for_each_reloc(ctx, 0))
+	if (for_each_reloc(ctx, f, 0))
 		return -1;
 
 	nrelocs = ctx->nrelocs;
@@ -324,7 +302,7 @@
 	ctx->nrelocs = 0;
 	ctx->emitted_relocs = calloc(nrelocs, sizeof(Elf64_Addr));
 	/* Write out the relocations into the emitted_relocs array. */
-	if (for_each_reloc(ctx, 1))
+	if (for_each_reloc(ctx, f, 1))
 		return -1;
 
 	if (ctx->nrelocs != nrelocs) {
@@ -618,7 +596,7 @@
 	return ret;
 }
 
-static int rmodule_init(struct rmod_context *ctx, const struct buffer *elfin)
+int rmodule_init(struct rmod_context *ctx, const struct buffer *elfin)
 {
 	struct parsed_elf *pelf;
 	int i;
@@ -670,7 +648,7 @@
 	return ret;
 }
 
-static void rmodule_cleanup(struct rmod_context *ctx)
+void rmodule_cleanup(struct rmod_context *ctx)
 {
 	free(ctx->emitted_relocs);
 	parsed_elf_destroy(&ctx->pelf);
@@ -684,7 +662,7 @@
 	if (rmodule_init(&ctx, elfin))
 		goto out;
 
-	if (collect_relocations(&ctx))
+	if (rmodule_collect_relocations(&ctx, NULL))
 		goto out;
 
 	if (populate_rmodule_info(&ctx))