@@ -3,8 +3,10 @@ objtool-y += arch/$(SRCARCH)/
objtool-y += weak.o
objtool-$(SUBCMD_CHECK) += check.o
+objtool-$(SUBCMD_CHECK) += cfi.o
objtool-$(SUBCMD_CHECK) += special.o
objtool-$(SUBCMD_ORC) += check.o
+objtool-$(SUBCMD_ORC) += cfi.o
objtool-$(SUBCMD_ORC) += orc_gen.o
objtool-$(SUBCMD_ORC) += orc_dump.o
new file mode 100644
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2015-2017 Josh Poimboeuf <jpoimboe@redhat.com>
+ */
+
+#include <stdlib.h>
+#include <sys/mman.h>
+
+#include <objtool/cfi.h>
+#include <objtool/builtin.h>
+#include <objtool/warn.h>
+
+unsigned long nr_cfi, nr_cfi_reused, nr_cfi_cache;
+
+struct cfi_init_state initial_func_cfi;
+struct cfi_state init_cfi;
+struct cfi_state func_cfi;
+
+void init_cfi_state(struct cfi_state *cfi)
+{
+ int i;
+
+ for (i = 0; i < CFI_NUM_REGS; i++) {
+ cfi->regs[i].base = CFI_UNDEFINED;
+ cfi->vals[i].base = CFI_UNDEFINED;
+ }
+ cfi->cfa.base = CFI_UNDEFINED;
+ cfi->drap_reg = CFI_UNDEFINED;
+ cfi->drap_offset = -1;
+}
+
+static struct cfi_state *cfi_alloc(void)
+{
+ struct cfi_state *cfi = calloc(sizeof(struct cfi_state), 1);
+
+ if (!cfi) {
+ WARN("calloc failed");
+ exit(1);
+ }
+ nr_cfi++;
+ return cfi;
+}
+
+static int cfi_bits;
+static struct hlist_head *cfi_hash;
+
+bool cficmp(struct cfi_state *cfi1, struct cfi_state *cfi2)
+{
+ return memcmp((void *)cfi1 + sizeof(cfi1->hash),
+ (void *)cfi2 + sizeof(cfi2->hash),
+ sizeof(struct cfi_state) - sizeof(struct hlist_node));
+}
+
+static inline u32 cfi_key(struct cfi_state *cfi)
+{
+ return jhash((void *)cfi + sizeof(cfi->hash),
+ sizeof(*cfi) - sizeof(cfi->hash), 0);
+}
+
+struct cfi_state *cfi_hash_find_or_add(struct cfi_state *cfi)
+{
+ struct hlist_head *head = &cfi_hash[hash_min(cfi_key(cfi), cfi_bits)];
+ struct cfi_state *obj;
+
+ hlist_for_each_entry(obj, head, hash) {
+ if (!cficmp(cfi, obj)) {
+ nr_cfi_cache++;
+ return obj;
+ }
+ }
+
+ obj = cfi_alloc();
+ *obj = *cfi;
+ hlist_add_head(&obj->hash, head);
+
+ return obj;
+}
+
+void cfi_hash_add(struct cfi_state *cfi)
+{
+ struct hlist_head *head = &cfi_hash[hash_min(cfi_key(cfi), cfi_bits)];
+
+ hlist_add_head(&cfi->hash, head);
+}
+
+void *cfi_hash_alloc(unsigned long size)
+{
+ cfi_bits = max(10, ilog2(size));
+ cfi_hash = mmap(NULL, sizeof(struct hlist_head) << cfi_bits,
+ PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANON, -1, 0);
+ if (cfi_hash == (void *)-1L) {
+ WARN("mmap fail cfi_hash");
+ cfi_hash = NULL;
+ } else if (stats) {
+ printf("cfi_bits: %d\n", cfi_bits);
+ }
+
+ return cfi_hash;
+}
+
+void set_func_state(struct cfi_state *state)
+{
+ state->cfa = initial_func_cfi.cfa;
+ memcpy(&state->regs, &initial_func_cfi.regs,
+ CFI_NUM_REGS * sizeof(struct cfi_reg));
+ state->stack_size = initial_func_cfi.cfa.offset;
+}
@@ -27,12 +27,6 @@ struct alternative {
bool skip_orig;
};
-static unsigned long nr_cfi, nr_cfi_reused, nr_cfi_cache;
-
-static struct cfi_init_state initial_func_cfi;
-static struct cfi_state init_cfi;
-static struct cfi_state func_cfi;
-
struct instruction *find_insn(struct objtool_file *file,
struct section *sec, unsigned long offset)
{
@@ -249,19 +243,6 @@ static bool dead_end_function(struct objtool_file *file, struct symbol *func)
return __dead_end_function(file, func, 0);
}
-static void init_cfi_state(struct cfi_state *cfi)
-{
- int i;
-
- for (i = 0; i < CFI_NUM_REGS; i++) {
- cfi->regs[i].base = CFI_UNDEFINED;
- cfi->vals[i].base = CFI_UNDEFINED;
- }
- cfi->cfa.base = CFI_UNDEFINED;
- cfi->drap_reg = CFI_UNDEFINED;
- cfi->drap_offset = -1;
-}
-
static void init_insn_state(struct insn_state *state, struct section *sec)
{
memset(state, 0, sizeof(*state));
@@ -276,75 +257,6 @@ static void init_insn_state(struct insn_state *state, struct section *sec)
state->noinstr = sec->noinstr;
}
-static struct cfi_state *cfi_alloc(void)
-{
- struct cfi_state *cfi = calloc(sizeof(struct cfi_state), 1);
- if (!cfi) {
- WARN("calloc failed");
- exit(1);
- }
- nr_cfi++;
- return cfi;
-}
-
-static int cfi_bits;
-static struct hlist_head *cfi_hash;
-
-static inline bool cficmp(struct cfi_state *cfi1, struct cfi_state *cfi2)
-{
- return memcmp((void *)cfi1 + sizeof(cfi1->hash),
- (void *)cfi2 + sizeof(cfi2->hash),
- sizeof(struct cfi_state) - sizeof(struct hlist_node));
-}
-
-static inline u32 cfi_key(struct cfi_state *cfi)
-{
- return jhash((void *)cfi + sizeof(cfi->hash),
- sizeof(*cfi) - sizeof(cfi->hash), 0);
-}
-
-static struct cfi_state *cfi_hash_find_or_add(struct cfi_state *cfi)
-{
- struct hlist_head *head = &cfi_hash[hash_min(cfi_key(cfi), cfi_bits)];
- struct cfi_state *obj;
-
- hlist_for_each_entry(obj, head, hash) {
- if (!cficmp(cfi, obj)) {
- nr_cfi_cache++;
- return obj;
- }
- }
-
- obj = cfi_alloc();
- *obj = *cfi;
- hlist_add_head(&obj->hash, head);
-
- return obj;
-}
-
-static void cfi_hash_add(struct cfi_state *cfi)
-{
- struct hlist_head *head = &cfi_hash[hash_min(cfi_key(cfi), cfi_bits)];
-
- hlist_add_head(&cfi->hash, head);
-}
-
-static void *cfi_hash_alloc(unsigned long size)
-{
- cfi_bits = max(10, ilog2(size));
- cfi_hash = mmap(NULL, sizeof(struct hlist_head) << cfi_bits,
- PROT_READ|PROT_WRITE,
- MAP_PRIVATE|MAP_ANON, -1, 0);
- if (cfi_hash == (void *)-1L) {
- WARN("mmap fail cfi_hash");
- cfi_hash = NULL;
- } else if (stats) {
- printf("cfi_bits: %d\n", cfi_bits);
- }
-
- return cfi_hash;
-}
-
static unsigned long nr_insns;
static unsigned long nr_insns_visited;
@@ -1866,14 +1778,6 @@ static int add_jump_table_alts(struct objtool_file *file)
return 0;
}
-static void set_func_state(struct cfi_state *state)
-{
- state->cfa = initial_func_cfi.cfa;
- memcpy(&state->regs, &initial_func_cfi.regs,
- CFI_NUM_REGS * sizeof(struct cfi_reg));
- state->stack_size = initial_func_cfi.cfa.offset;
-}
-
static int read_unwind_hints(struct objtool_file *file)
{
struct cfi_state cfi = init_cfi;
@@ -37,4 +37,16 @@ struct cfi_state {
bool end;
};
+void init_cfi_state(struct cfi_state *cfi);
+struct cfi_state *cfi_hash_find_or_add(struct cfi_state *cfi);
+void cfi_hash_add(struct cfi_state *cfi);
+void *cfi_hash_alloc(unsigned long size);
+bool cficmp(struct cfi_state *cfi1, struct cfi_state *cfi2);
+void set_func_state(struct cfi_state *state);
+
+extern unsigned long nr_cfi, nr_cfi_reused, nr_cfi_cache;
+extern struct cfi_init_state initial_func_cfi;
+extern struct cfi_state init_cfi;
+extern struct cfi_state func_cfi;
+
#endif /* _OBJTOOL_CFI_H */