When an instruction warning (WARN_INSN) or backtrace (BT_INSN) is issued, disassemble the instruction to provide more context.
Unified · Split
| @@ -4792,11 +4792,34 @@ static void free_insns(struct objtool_file *file) · 4791 unmodified lines | ||
| 4792 | 4792 | free(chunk->addr); |
| 4793 | 4793 | } |
| 4794 | 4794 | |
| 4795 | +static struct disas_context *objtool_disas_ctx; | |
| 4796 | + | |
| 4797 | +const char *objtool_disas_insn(struct instruction *insn) | |
| 4798 | +{ | |
| 4799 | + struct disas_context *dctx = objtool_disas_ctx; | |
| 4800 | + | |
| 4801 | + if (!dctx) | |
| 4802 | + return ""; | |
| 4803 | + | |
| 4804 | + disas_insn(dctx, insn); | |
| 4805 | + return disas_result(dctx); | |
| 4806 | +} | |
| 4807 | + | |
| 4795 | 4808 | int check(struct objtool_file *file) |
| 4796 | 4809 | { |
| 4797 | − struct disas_context *disas_ctx; | |
| 4810 | + struct disas_context *disas_ctx = NULL; | |
| 4798 | 4811 | int ret = 0, warnings = 0; |
| 4799 | 4812 | |
| 4813 | + /* | |
| 4814 | + * If the verbose or backtrace option is used then we need a | |
| 4815 | + * disassembly context to disassemble instruction or function | |
| 4816 | + * on warning or backtrace. | |
| 4817 | + */ | |
| 4818 | + if (opts.verbose || opts.backtrace) { | |
| 4819 | + disas_ctx = disas_context_create(file); | |
| 4820 | + objtool_disas_ctx = disas_ctx; | |
| 4821 | + } | |
| 4822 | + | |
| 4800 | 4823 | arch_initial_func_cfi_state(&initial_func_cfi); |
| 4801 | 4824 | init_cfi_state(&init_cfi); |
| 4802 | 4825 | init_cfi_state(&func_cfi); |
| @@ -4936,11 +4959,12 @@ out: · 133 unmodified lines | ||
| 4936 | 4959 | if (opts.verbose) { |
| 4937 | 4960 | if (opts.werror && warnings) |
| 4938 | 4961 | WARN("%d warning(s) upgraded to errors", warnings); |
| 4939 | − disas_ctx = disas_context_create(file); | |
| 4940 | − if (disas_ctx) { | |
| 4941 | − disas_warned_funcs(disas_ctx); | |
| 4942 | − disas_context_destroy(disas_ctx); | |
| 4943 | − } | |
| 4962 | + disas_warned_funcs(disas_ctx); | |
| 4963 | + } | |
| 4964 | + | |
| 4965 | + if (disas_ctx) { | |
| 4966 | + disas_context_destroy(disas_ctx); | |
| 4967 | + objtool_disas_ctx = NULL; | |
| 4944 | 4968 | } |
| 4945 | 4969 | |
| 4946 | 4970 | free_insns(file); |
| @@ -303,7 +303,7 @@ void disas_context_destroy(struct disas_context *dctx) · 302 unmodified lines | ||
| 303 | 303 | free(dctx); |
| 304 | 304 | } |
| 305 | 305 | |
| 306 | −static char *disas_result(struct disas_context *dctx) | |
| 306 | +char *disas_result(struct disas_context *dctx) | |
| 307 | 307 | { |
| 308 | 308 | return dctx->result; |
| 309 | 309 | } |
| @@ -311,8 +311,7 @@ static char *disas_result(struct disas_context *dctx) · 1 unmodified line | ||
| 311 | 311 | /* |
| 312 | 312 | * Disassemble a single instruction. Return the size of the instruction. |
| 313 | 313 | */ |
| 314 | −static size_t disas_insn(struct disas_context *dctx, | |
| 315 | − struct instruction *insn) | |
| 314 | +size_t disas_insn(struct disas_context *dctx, struct instruction *insn) | |
| 316 | 315 | { |
| 317 | 316 | disassembler_ftype disasm = dctx->disassembler; |
| 318 | 317 | struct disassemble_info *dinfo = &dctx->info; |
| @@ -141,4 +141,6 @@ struct instruction *next_insn_same_sec(struct objtool_file *file, struct instruc · 140 unmodified lines | ||
| 141 | 141 | insn && insn->offset < sym->offset + sym->len; \ |
| 142 | 142 | insn = next_insn_same_sec(file, insn)) |
| 143 | 143 | |
| 144 | +const char *objtool_disas_insn(struct instruction *insn); | |
| 145 | + | |
| 144 | 146 | #endif /* _CHECK_H */ |
| @@ -17,6 +17,8 @@ void disas_warned_funcs(struct disas_context *dctx); · 16 unmodified lines | ||
| 17 | 17 | int disas_info_init(struct disassemble_info *dinfo, |
| 18 | 18 | int arch, int mach32, int mach64, |
| 19 | 19 | const char *options); |
| 20 | +size_t disas_insn(struct disas_context *dctx, struct instruction *insn); | |
| 21 | +char *disas_result(struct disas_context *dctx); | |
| 20 | 22 | |
| 21 | 23 | #else /* DISAS */ |
| 22 | 24 | |
| @@ -38,6 +40,17 @@ static inline int disas_info_init(struct disassemble_info *dinfo, · 15 unmodified lines | ||
| 38 | 40 | return -1; |
| 39 | 41 | } |
| 40 | 42 | |
| 43 | +static inline size_t disas_insn(struct disas_context *dctx, | |
| 44 | + struct instruction *insn) | |
| 45 | +{ | |
| 46 | + return -1; | |
| 47 | +} | |
| 48 | + | |
| 49 | +static inline char *disas_result(struct disas_context *dctx) | |
| 50 | +{ | |
| 51 | + return NULL; | |
| 52 | +} | |
| 53 | + | |
| 41 | 54 | #endif /* DISAS */ |
| 42 | 55 | |
| 43 | 56 | #endif /* _DISAS_H */ |
| @@ -77,9 +77,11 @@ static inline char *offstr(struct section *sec, unsigned long offset) · 76 unmodified lines | ||
| 77 | 77 | #define WARN_INSN(insn, format, ...) \ |
| 78 | 78 | ({ \ |
| 79 | 79 | struct instruction *_insn = (insn); \ |
| 80 | − if (!_insn->sym || !_insn->sym->warned) \ | |
| 80 | + if (!_insn->sym || !_insn->sym->warned) { \ | |
| 81 | 81 | WARN_FUNC(_insn->sec, _insn->offset, format, \ |
| 82 | 82 | ##__VA_ARGS__); \ |
| 83 | + BT_INSN(_insn, ""); \ | |
| 84 | + } \ | |
| 83 | 85 | if (_insn->sym) \ |
| 84 | 86 | _insn->sym->warned = 1; \ |
| 85 | 87 | }) |
| @@ -87,10 +89,14 @@ static inline char *offstr(struct section *sec, unsigned long offset) · 1 unmodified line | ||
| 87 | 89 | #define BT_INSN(insn, format, ...) \ |
| 88 | 90 | ({ \ |
| 89 | 91 | if (opts.verbose || opts.backtrace) { \ |
| 90 | − struct instruction *_insn = (insn); \ | |
| 91 | − char *_str = offstr(_insn->sec, _insn->offset); \ | |
| 92 | − WARN(" %s: " format, _str, ##__VA_ARGS__); \ | |
| 93 | − free(_str); \ | |
| 92 | + struct instruction *__insn = (insn); \ | |
| 93 | + char *_str = offstr(__insn->sec, __insn->offset); \ | |
| 94 | + const char *_istr = objtool_disas_insn(__insn); \ | |
| 95 | + int _len; \ | |
| 96 | + _len = snprintf(NULL, 0, " %s: " format, _str, ##__VA_ARGS__); \ | |
| 97 | + _len = (_len < 50) ? 50 - _len : 0; \ | |
| 98 | + WARN(" %s: " format " %*s%s", _str, ##__VA_ARGS__, _len, "", _istr); \ | |
| 99 | + free(_str); \ | |
| 94 | 100 | } \ |
| 95 | 101 | }) |
| 96 | 102 | |