[RFC PATCH v1 02/23] objtool: Reorganize instruction-related code

From: Youling Tang
Date: Tue Jun 20 2023 - 03:47:31 EST


From: "Madhavan T. Venkataraman" <madvenka@xxxxxxxxxxxxxxxxxxx>

check.c implements static stack validation. But the instruction-related
code that it contains can be shared with other types of validation. E.g.,
dynamic FP validation. Move the instruction-related code to its own files
- insn.h and insn.c.

Signed-off-by: Madhavan T. Venkataraman <madvenka@xxxxxxxxxxxxxxxxxxx>
---
tools/objtool/Build | 1 +
tools/objtool/check.c | 231 --------------------------
tools/objtool/include/objtool/check.h | 92 +---------
tools/objtool/include/objtool/insn.h | 163 ++++++++++++++++++
tools/objtool/insn.c | 195 ++++++++++++++++++++++
5 files changed, 360 insertions(+), 322 deletions(-)
create mode 100644 tools/objtool/include/objtool/insn.h
create mode 100644 tools/objtool/insn.c

diff --git a/tools/objtool/Build b/tools/objtool/Build
index 9f23d1f4c716..c04e36267379 100644
--- a/tools/objtool/Build
+++ b/tools/objtool/Build
@@ -6,6 +6,7 @@ objtool-y += check.o
objtool-y += special.o
objtool-y += builtin-check.o
objtool-y += cfi.o
+objtool-y += insn.o
objtool-y += elf.o
objtool-y += objtool.o

diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 803764f4d4d8..619f7467e39c 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -28,121 +28,6 @@ struct alternative {
bool skip_orig;
};

-struct instruction *find_insn(struct objtool_file *file,
- struct section *sec, unsigned long offset)
-{
- struct instruction *insn;
-
- hash_for_each_possible(file->insn_hash, insn, hash, sec_offset_hash(sec, offset)) {
- if (insn->sec == sec && insn->offset == offset)
- return insn;
- }
-
- return NULL;
-}
-
-struct instruction *next_insn_same_sec(struct objtool_file *file,
- struct instruction *insn)
-{
- if (insn->idx == INSN_CHUNK_MAX)
- return find_insn(file, insn->sec, insn->offset + insn->len);
-
- insn++;
- if (!insn->len)
- return NULL;
-
- return insn;
-}
-
-static struct instruction *next_insn_same_func(struct objtool_file *file,
- struct instruction *insn)
-{
- struct instruction *next = next_insn_same_sec(file, insn);
- struct symbol *func = insn_func(insn);
-
- if (!func)
- return NULL;
-
- if (next && insn_func(next) == func)
- return next;
-
- /* Check if we're already in the subfunction: */
- if (func == func->cfunc)
- return NULL;
-
- /* Move to the subfunction: */
- return find_insn(file, func->cfunc->sec, func->cfunc->offset);
-}
-
-static struct instruction *prev_insn_same_sec(struct objtool_file *file,
- struct instruction *insn)
-{
- if (insn->idx == 0) {
- if (insn->prev_len)
- return find_insn(file, insn->sec, insn->offset - insn->prev_len);
- return NULL;
- }
-
- return insn - 1;
-}
-
-static struct instruction *prev_insn_same_sym(struct objtool_file *file,
- struct instruction *insn)
-{
- struct instruction *prev = prev_insn_same_sec(file, insn);
-
- if (prev && insn_func(prev) == insn_func(insn))
- return prev;
-
- return NULL;
-}
-
-#define for_each_insn(file, insn) \
- for (struct section *__sec, *__fake = (struct section *)1; \
- __fake; __fake = NULL) \
- for_each_sec(file, __sec) \
- sec_for_each_insn(file, __sec, insn)
-
-#define func_for_each_insn(file, func, insn) \
- for (insn = find_insn(file, func->sec, func->offset); \
- insn; \
- insn = next_insn_same_func(file, insn))
-
-#define sym_for_each_insn(file, sym, insn) \
- for (insn = find_insn(file, sym->sec, sym->offset); \
- insn && insn->offset < sym->offset + sym->len; \
- insn = next_insn_same_sec(file, insn))
-
-#define sym_for_each_insn_continue_reverse(file, sym, insn) \
- for (insn = prev_insn_same_sec(file, insn); \
- insn && insn->offset >= sym->offset; \
- insn = prev_insn_same_sec(file, insn))
-
-#define sec_for_each_insn_from(file, insn) \
- for (; insn; insn = next_insn_same_sec(file, insn))
-
-#define sec_for_each_insn_continue(file, insn) \
- for (insn = next_insn_same_sec(file, insn); insn; \
- insn = next_insn_same_sec(file, insn))
-
-static inline struct symbol *insn_call_dest(struct instruction *insn)
-{
- if (insn->type == INSN_JUMP_DYNAMIC ||
- insn->type == INSN_CALL_DYNAMIC)
- return NULL;
-
- return insn->_call_dest;
-}
-
-static inline struct reloc *insn_jump_table(struct instruction *insn)
-{
- if (insn->type == INSN_JUMP_DYNAMIC ||
- insn->type == INSN_CALL_DYNAMIC)
- return insn->_jump_table;
-
- return NULL;
-}
-
static bool is_jump_table_jump(struct instruction *insn)
{
struct alt_group *alt_group = insn->alt_group;
@@ -282,21 +167,6 @@ static bool dead_end_function(struct objtool_file *file, struct symbol *func)
return __dead_end_function(file, func, 0);
}

-static void init_insn_state(struct objtool_file *file, struct insn_state *state,
- struct section *sec)
-{
- memset(state, 0, sizeof(*state));
- init_cfi_state(&state->cfi);
-
- /*
- * We need the full vmlinux for noinstr validation, otherwise we can
- * not correctly determine insn_call_dest(insn)->sec (external symbols
- * do not have a section).
- */
- if (opts.link && opts.noinstr && sec)
- state->noinstr = sec->noinstr;
-}
-
static unsigned long nr_insns;
static unsigned long nr_insns_visited;

@@ -501,19 +371,6 @@ static int init_pv_ops(struct objtool_file *file)
return 0;
}

-static struct instruction *find_last_insn(struct objtool_file *file,
- struct section *sec)
-{
- struct instruction *insn = NULL;
- unsigned int offset;
- unsigned int end = (sec->sh.sh_size > 10) ? sec->sh.sh_size - 10 : 0;
-
- for (offset = sec->sh.sh_size - 1; offset >= end && !insn; offset--)
- insn = find_insn(file, sec, offset);
-
- return insn;
-}
-
/*
* Mark "ud2" instructions and manually annotated dead ends.
*/
@@ -1263,26 +1120,6 @@ __weak bool arch_is_rethunk(struct symbol *sym)
return false;
}

-static struct reloc *insn_reloc(struct objtool_file *file, struct instruction *insn)
-{
- struct reloc *reloc;
-
- if (insn->no_reloc)
- return NULL;
-
- if (!file)
- return NULL;
-
- reloc = find_reloc_by_dest_range(file->elf, insn->sec,
- insn->offset, insn->len);
- if (!reloc) {
- insn->no_reloc = 1;
- return NULL;
- }
-
- return reloc;
-}
-
static void remove_insn_ops(struct instruction *insn)
{
struct stack_op *op, *next;
@@ -1446,24 +1283,6 @@ static void add_return_call(struct objtool_file *file, struct instruction *insn,
list_add_tail(&insn->call_node, &file->return_thunk_list);
}

-static bool is_first_func_insn(struct objtool_file *file,
- struct instruction *insn, struct symbol *sym)
-{
- if (insn->offset == sym->offset)
- return true;
-
- /* Allow direct CALL/JMP past ENDBR */
- if (opts.ibt) {
- struct instruction *prev = prev_insn_same_sym(file, insn);
-
- if (prev && prev->type == INSN_ENDBR &&
- insn->offset == sym->offset + prev->len)
- return true;
- }
-
- return false;
-}
-
/*
* A sibling call is a tail-call to another symbol -- to differentiate from a
* recursive tail-call which is to the same symbol.
@@ -3224,56 +3043,6 @@ static int handle_insn_ops(struct instruction *insn,
return 0;
}

-static bool insn_cfi_match(struct instruction *insn, struct cfi_state *cfi2)
-{
- struct cfi_state *cfi1 = insn->cfi;
- int i;
-
- if (!cfi1) {
- WARN("CFI missing");
- return false;
- }
-
- if (memcmp(&cfi1->cfa, &cfi2->cfa, sizeof(cfi1->cfa))) {
-
- WARN_FUNC("stack state mismatch: cfa1=%d%+d cfa2=%d%+d",
- insn->sec, insn->offset,
- cfi1->cfa.base, cfi1->cfa.offset,
- cfi2->cfa.base, cfi2->cfa.offset);
-
- } else if (memcmp(&cfi1->regs, &cfi2->regs, sizeof(cfi1->regs))) {
- for (i = 0; i < CFI_NUM_REGS; i++) {
- if (!memcmp(&cfi1->regs[i], &cfi2->regs[i],
- sizeof(struct cfi_reg)))
- continue;
-
- WARN_FUNC("stack state mismatch: reg1[%d]=%d%+d reg2[%d]=%d%+d",
- insn->sec, insn->offset,
- i, cfi1->regs[i].base, cfi1->regs[i].offset,
- i, cfi2->regs[i].base, cfi2->regs[i].offset);
- break;
- }
-
- } else if (cfi1->type != cfi2->type) {
-
- WARN_FUNC("stack state mismatch: type1=%d type2=%d",
- insn->sec, insn->offset, cfi1->type, cfi2->type);
-
- } else if (cfi1->drap != cfi2->drap ||
- (cfi1->drap && cfi1->drap_reg != cfi2->drap_reg) ||
- (cfi1->drap && cfi1->drap_offset != cfi2->drap_offset)) {
-
- WARN_FUNC("stack state mismatch: drap1=%d(%d,%d) drap2=%d(%d,%d)",
- insn->sec, insn->offset,
- cfi1->drap, cfi1->drap_reg, cfi1->drap_offset,
- cfi2->drap, cfi2->drap_reg, cfi2->drap_offset);
-
- } else
- return true;
-
- return false;
-}
-
static inline bool func_uaccess_safe(struct symbol *func)
{
if (func)
diff --git a/tools/objtool/include/objtool/check.h b/tools/objtool/include/objtool/check.h
index 3e7c7004f7df..450ebc092b1f 100644
--- a/tools/objtool/include/objtool/check.h
+++ b/tools/objtool/include/objtool/check.h
@@ -7,17 +7,7 @@
#define _CHECK_H

#include <stdbool.h>
-#include <objtool/cfi.h>
-#include <objtool/arch.h>
-
-struct insn_state {
- struct cfi_state cfi;
- unsigned int uaccess_stack;
- bool uaccess;
- bool df;
- bool noinstr;
- s8 instr;
-};
+#include <objtool/insn.h>

struct alt_group {
/*
@@ -36,89 +26,9 @@ struct alt_group {
struct cfi_state **cfi;
};

-#define INSN_CHUNK_BITS 8
-#define INSN_CHUNK_SIZE (1 << INSN_CHUNK_BITS)
-#define INSN_CHUNK_MAX (INSN_CHUNK_SIZE - 1)
-
-struct instruction {
- struct hlist_node hash;
- struct list_head call_node;
- struct section *sec;
- unsigned long offset;
- unsigned long immediate;
-
- u8 len;
- u8 prev_len;
- u8 type;
- s8 instr;
-
- u32 idx : INSN_CHUNK_BITS,
- dead_end : 1,
- ignore : 1,
- ignore_alts : 1,
- hint : 1,
- save : 1,
- restore : 1,
- retpoline_safe : 1,
- noendbr : 1,
- entry : 1,
- visited : 4,
- no_reloc : 1;
- /* 10 bit hole */
-
- struct alt_group *alt_group;
- struct instruction *jump_dest;
- struct instruction *first_jump_src;
- union {
- struct symbol *_call_dest;
- struct reloc *_jump_table;
- };
- struct alternative *alts;
- struct symbol *sym;
- struct stack_op *stack_ops;
- struct cfi_state *cfi;
-};
-
-static inline struct symbol *insn_func(struct instruction *insn)
-{
- struct symbol *sym = insn->sym;
-
- if (sym && sym->type != STT_FUNC)
- sym = NULL;
-
- return sym;
-}
-
#define VISITED_BRANCH 0x01
#define VISITED_BRANCH_UACCESS 0x02
#define VISITED_BRANCH_MASK 0x03
#define VISITED_ENTRY 0x04

-static inline bool is_static_jump(struct instruction *insn)
-{
- return insn->type == INSN_JUMP_CONDITIONAL ||
- insn->type == INSN_JUMP_UNCONDITIONAL;
-}
-
-static inline bool is_dynamic_jump(struct instruction *insn)
-{
- return insn->type == INSN_JUMP_DYNAMIC ||
- insn->type == INSN_JUMP_DYNAMIC_CONDITIONAL;
-}
-
-static inline bool is_jump(struct instruction *insn)
-{
- return is_static_jump(insn) || is_dynamic_jump(insn);
-}
-
-struct instruction *find_insn(struct objtool_file *file,
- struct section *sec, unsigned long offset);
-
-struct instruction *next_insn_same_sec(struct objtool_file *file, struct instruction *insn);
-
-#define sec_for_each_insn(file, _sec, insn) \
- for (insn = find_insn(file, _sec, 0); \
- insn && insn->sec == _sec; \
- insn = next_insn_same_sec(file, insn))
-
#endif /* _CHECK_H */
diff --git a/tools/objtool/include/objtool/insn.h b/tools/objtool/include/objtool/insn.h
new file mode 100644
index 000000000000..edd46b5ea1e4
--- /dev/null
+++ b/tools/objtool/include/objtool/insn.h
@@ -0,0 +1,163 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@xxxxxxxxxx>
+ */
+
+#ifndef _INSN_H
+#define _INSN_H
+
+#include <objtool/objtool.h>
+#include <objtool/arch.h>
+
+#define INSN_CHUNK_BITS 8
+#define INSN_CHUNK_SIZE (1 << INSN_CHUNK_BITS)
+#define INSN_CHUNK_MAX (INSN_CHUNK_SIZE - 1)
+
+struct insn_state {
+ struct cfi_state cfi;
+ unsigned int uaccess_stack;
+ bool uaccess;
+ bool df;
+ bool noinstr;
+ s8 instr;
+};
+
+struct instruction {
+ struct hlist_node hash;
+ struct list_head call_node;
+ struct section *sec;
+ unsigned long offset;
+ unsigned long immediate;
+
+ u8 len;
+ u8 prev_len;
+ u8 type;
+ s8 instr;
+
+ u32 idx : INSN_CHUNK_BITS,
+ dead_end : 1,
+ ignore : 1,
+ ignore_alts : 1,
+ hint : 1,
+ save : 1,
+ restore : 1,
+ retpoline_safe : 1,
+ noendbr : 1,
+ entry : 1,
+ visited : 4,
+ no_reloc : 1;
+ /* 10 bit hole */
+
+ struct alt_group *alt_group;
+ struct instruction *jump_dest;
+ struct instruction *first_jump_src;
+ union {
+ struct symbol *_call_dest;
+ struct reloc *_jump_table;
+ };
+ struct alternative *alts;
+ struct symbol *sym;
+ struct stack_op *stack_ops;
+ struct cfi_state *cfi;
+};
+
+static inline struct symbol *insn_func(struct instruction *insn)
+{
+ struct symbol *sym = insn->sym;
+
+ if (sym && sym->type != STT_FUNC)
+ sym = NULL;
+
+ return sym;
+}
+
+static inline bool is_static_jump(struct instruction *insn)
+{
+ return insn->type == INSN_JUMP_CONDITIONAL ||
+ insn->type == INSN_JUMP_UNCONDITIONAL;
+}
+
+static inline bool is_dynamic_jump(struct instruction *insn)
+{
+ return insn->type == INSN_JUMP_DYNAMIC ||
+ insn->type == INSN_JUMP_DYNAMIC_CONDITIONAL;
+}
+
+static inline bool is_jump(struct instruction *insn)
+{
+ return is_static_jump(insn) || is_dynamic_jump(insn);
+}
+
+static inline struct symbol *insn_call_dest(struct instruction *insn)
+{
+ if (insn->type == INSN_JUMP_DYNAMIC ||
+ insn->type == INSN_CALL_DYNAMIC)
+ return NULL;
+
+ return insn->_call_dest;
+}
+
+static inline struct reloc *insn_jump_table(struct instruction *insn)
+{
+ if (insn->type == INSN_JUMP_DYNAMIC ||
+ insn->type == INSN_CALL_DYNAMIC)
+ return insn->_jump_table;
+
+ return NULL;
+}
+
+void init_insn_state(struct objtool_file *file, struct insn_state *state,
+ struct section *sec);
+struct instruction *find_insn(struct objtool_file *file,
+ struct section *sec, unsigned long offset);
+struct instruction *find_last_insn(struct objtool_file *file,
+ struct section *sec);
+struct instruction *prev_insn_same_sec(struct objtool_file *file,
+ struct instruction *insn);
+struct instruction *prev_insn_same_sym(struct objtool_file *file,
+ struct instruction *insn);
+struct instruction *next_insn_same_sec(struct objtool_file *file,
+ struct instruction *insn);
+struct instruction *next_insn_same_func(struct objtool_file *file,
+ struct instruction *insn);
+struct reloc *insn_reloc(struct objtool_file *file, struct instruction *insn);
+bool insn_cfi_match(struct instruction *insn, struct cfi_state *cfi2);
+bool same_function(struct instruction *insn1, struct instruction *insn2);
+bool is_first_func_insn(struct objtool_file *file,
+ struct instruction *insn, struct symbol *sym);
+
+
+#define for_each_insn(file, insn) \
+ for (struct section *__sec, *__fake = (struct section *)1; \
+ __fake; __fake = NULL) \
+ for_each_sec(file, __sec) \
+ sec_for_each_insn(file, __sec, insn)
+
+#define sec_for_each_insn(file, _sec, insn) \
+ for (insn = find_insn(file, _sec, 0); \
+ insn && insn->sec == _sec; \
+ insn = next_insn_same_sec(file, insn))
+
+#define func_for_each_insn(file, func, insn) \
+ for (insn = find_insn(file, func->sec, func->offset); \
+ insn; \
+ insn = next_insn_same_func(file, insn))
+
+#define sym_for_each_insn(file, sym, insn) \
+ for (insn = find_insn(file, sym->sec, sym->offset); \
+ insn && insn->offset < sym->offset + sym->len; \
+ insn = next_insn_same_sec(file, insn))
+
+#define sym_for_each_insn_continue_reverse(file, sym, insn) \
+ for (insn = prev_insn_same_sec(file, insn); \
+ insn && insn->offset >= sym->offset; \
+ insn = prev_insn_same_sec(file, insn))
+
+#define sec_for_each_insn_from(file, insn) \
+ for (; insn; insn = next_insn_same_sec(file, insn))
+
+#define sec_for_each_insn_continue(file, insn) \
+ for (insn = next_insn_same_sec(file, insn); insn; \
+ insn = next_insn_same_sec(file, insn))
+
+#endif /* _INSN_H */
diff --git a/tools/objtool/insn.c b/tools/objtool/insn.c
new file mode 100644
index 000000000000..c020cb84489d
--- /dev/null
+++ b/tools/objtool/insn.c
@@ -0,0 +1,195 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2015-2017 Josh Poimboeuf <jpoimboe@xxxxxxxxxx>
+ */
+
+#include <string.h>
+
+#include <objtool/builtin.h>
+#include <objtool/insn.h>
+#include <objtool/warn.h>
+
+struct instruction *find_insn(struct objtool_file *file,
+ struct section *sec, unsigned long offset)
+{
+ struct instruction *insn;
+
+ hash_for_each_possible(file->insn_hash, insn, hash, sec_offset_hash(sec, offset)) {
+ if (insn->sec == sec && insn->offset == offset)
+ return insn;
+ }
+
+ return NULL;
+}
+
+struct instruction *next_insn_same_sec(struct objtool_file *file,
+ struct instruction *insn)
+{
+ if (insn->idx == INSN_CHUNK_MAX)
+ return find_insn(file, insn->sec, insn->offset + insn->len);
+
+ insn++;
+ if (!insn->len)
+ return NULL;
+
+ return insn;
+}
+
+struct instruction *next_insn_same_func(struct objtool_file *file,
+ struct instruction *insn)
+{
+ struct instruction *next = next_insn_same_sec(file, insn);
+ struct symbol *func = insn_func(insn);
+
+ if (!func)
+ return NULL;
+
+ if (next && insn_func(next) == func)
+ return next;
+
+ /* Check if we're already in the subfunction: */
+ if (func == func->cfunc)
+ return NULL;
+
+ /* Move to the subfunction: */
+ return find_insn(file, func->cfunc->sec, func->cfunc->offset);
+}
+
+struct instruction *prev_insn_same_sec(struct objtool_file *file,
+ struct instruction *insn)
+{
+ if (insn->idx == 0) {
+ if (insn->prev_len)
+ return find_insn(file, insn->sec, insn->offset - insn->prev_len);
+ return NULL;
+ }
+
+ return insn - 1;
+}
+
+struct instruction *prev_insn_same_sym(struct objtool_file *file,
+ struct instruction *insn)
+{
+ struct instruction *prev = prev_insn_same_sec(file, insn);
+
+ if (prev && insn_func(prev) == insn_func(insn))
+ return prev;
+
+ return NULL;
+}
+
+void init_insn_state(struct objtool_file *file, struct insn_state *state,
+ struct section *sec)
+{
+ memset(state, 0, sizeof(*state));
+ init_cfi_state(&state->cfi);
+
+ /*
+ * We need the full vmlinux for noinstr validation, otherwise we can
+ * not correctly determine insn_call_dest(insn)->sec (external symbols
+ * do not have a section).
+ */
+ if (opts.link && opts.noinstr && sec)
+ state->noinstr = sec->noinstr;
+}
+
+struct instruction *find_last_insn(struct objtool_file *file,
+ struct section *sec)
+{
+ struct instruction *insn = NULL;
+ unsigned int offset;
+ unsigned int end = (sec->sh.sh_size > 10) ? sec->sh.sh_size - 10 : 0;
+
+ for (offset = sec->sh.sh_size - 1; offset >= end && !insn; offset--)
+ insn = find_insn(file, sec, offset);
+
+ return insn;
+}
+
+struct reloc *insn_reloc(struct objtool_file *file, struct instruction *insn)
+{
+ struct reloc *reloc;
+
+ if (insn->no_reloc)
+ return NULL;
+
+ if (!file)
+ return NULL;
+
+ reloc = find_reloc_by_dest_range(file->elf, insn->sec,
+ insn->offset, insn->len);
+ if (!reloc) {
+ insn->no_reloc = 1;
+ return NULL;
+ }
+
+ return reloc;
+}
+
+bool is_first_func_insn(struct objtool_file *file,
+ struct instruction *insn, struct symbol *sym)
+{
+ if (insn->offset == sym->offset)
+ return true;
+
+ /* Allow direct CALL/JMP past ENDBR */
+ if (opts.ibt) {
+ struct instruction *prev = prev_insn_same_sym(file, insn);
+
+ if (prev && prev->type == INSN_ENDBR &&
+ insn->offset == sym->offset + prev->len)
+ return true;
+ }
+
+ return false;
+}
+
+bool insn_cfi_match(struct instruction *insn, struct cfi_state *cfi2)
+{
+ struct cfi_state *cfi1 = insn->cfi;
+ int i;
+
+ if (!cfi1) {
+ WARN("CFI missing");
+ return false;
+ }
+
+ if (memcmp(&cfi1->cfa, &cfi2->cfa, sizeof(cfi1->cfa))) {
+
+ WARN_FUNC("stack state mismatch: cfa1=%d%+d cfa2=%d%+d",
+ insn->sec, insn->offset,
+ cfi1->cfa.base, cfi1->cfa.offset,
+ cfi2->cfa.base, cfi2->cfa.offset);
+
+ } else if (memcmp(&cfi1->regs, &cfi2->regs, sizeof(cfi1->regs))) {
+ for (i = 0; i < CFI_NUM_REGS; i++) {
+ if (!memcmp(&cfi1->regs[i], &cfi2->regs[i],
+ sizeof(struct cfi_reg)))
+ continue;
+
+ WARN_FUNC("stack state mismatch: reg1[%d]=%d%+d reg2[%d]=%d%+d",
+ insn->sec, insn->offset,
+ i, cfi1->regs[i].base, cfi1->regs[i].offset,
+ i, cfi2->regs[i].base, cfi2->regs[i].offset);
+ break;
+ }
+
+ } else if (cfi1->type != cfi2->type) {
+
+ WARN_FUNC("stack state mismatch: type1=%d type2=%d",
+ insn->sec, insn->offset, cfi1->type, cfi2->type);
+
+ } else if (cfi1->drap != cfi2->drap ||
+ (cfi1->drap && cfi1->drap_reg != cfi2->drap_reg) ||
+ (cfi1->drap && cfi1->drap_offset != cfi2->drap_offset)) {
+
+ WARN_FUNC("stack state mismatch: drap1=%d(%d,%d) drap2=%d(%d,%d)",
+ insn->sec, insn->offset,
+ cfi1->drap, cfi1->drap_reg, cfi1->drap_offset,
+ cfi2->drap, cfi2->drap_reg, cfi2->drap_offset);
+
+ } else
+ return true;
+
+ return false;
+}
--
2.39.2