summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--util/cbfstool/rmodule.c62
-rw-r--r--util/cbfstool/rmodule.h63
2 files changed, 82 insertions, 43 deletions
diff --git a/util/cbfstool/rmodule.c b/util/cbfstool/rmodule.c
index 03828f77c9bc..46c9384d50fc 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 @@ static int should_emit_aarch64(Elf64_Rela *rel)
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 @@ static struct arch_ops reloc_ops[] = {
* 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 @@ static int for_each_reloc(struct rmod_context *ctx, int do_emit)
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 @@ static int for_each_reloc(struct rmod_context *ctx, int do_emit)
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 @@ static int vaddr_cmp(const void *a, const void *b)
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 @@ static int collect_relocations(struct rmod_context *ctx)
* 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 @@ static int collect_relocations(struct rmod_context *ctx)
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 @@ out:
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 @@ out:
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 @@ int rmodule_create(const struct buffer *elfin, struct buffer *elfout)
if (rmodule_init(&ctx, elfin))
goto out;
- if (collect_relocations(&ctx))
+ if (rmodule_collect_relocations(&ctx, NULL))
goto out;
if (populate_rmodule_info(&ctx))
diff --git a/util/cbfstool/rmodule.h b/util/cbfstool/rmodule.h
index 4531f8d0b98e..9a6567741871 100644
--- a/util/cbfstool/rmodule.h
+++ b/util/cbfstool/rmodule.h
@@ -18,13 +18,74 @@
#ifndef TOOL_RMODULE_H
#define TOOL_RMODULE_H
-#include "elf.h"
+#include "elfparsing.h"
#include "common.h"
+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);
+};
+
+/*
+ * The fields in rmod_context are read-only to the user. These are
+ * exposed for easy shareability.
+ */
+struct rmod_context {
+ /* Ops to process relocations. */
+ const 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;
+};
+
+struct reloc_filter {
+ /* Return < 0 on error. 0 to ignore relocation and 1 to include
+ * relocation. */
+ int (*filter)(struct reloc_filter *f, const Elf64_Rela *r);
+ /* Pointer for filter provides */
+ void *context;
+};
+
/*
* Parse an ELF file within the elfin buffer and fill in the elfout buffer
* with a created rmodule in ELF format. Return 0 on success, < 0 on error.
*/
int rmodule_create(const struct buffer *elfin, struct buffer *elfout);
+/*
+ * Initialize an rmodule context from an ELF buffer. Returns 0 on scucess, < 0
+ * on error.
+ */
+int rmodule_init(struct rmod_context *ctx, const struct buffer *elfin);
+
+/*
+ * Collect all the relocations that apply to the program in
+ * nrelocs/emitted_relocs. One can optionally provide a reloc_filter object
+ * to help in relocation filtering. The filter function will be called twice:
+ * once for counting and once for emitting. The same response should be
+ * provided for each call. Returns 0 on success, < 0 on error.
+ */
+int rmodule_collect_relocations(struct rmod_context *c, struct reloc_filter *f);
+
+/* Clean up the memory consumed by the rmdoule context. */
+void rmodule_cleanup(struct rmod_context *ctx);
+
#endif /* TOOL_RMODULE_H */