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 | free(chunk->addr); | 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 | int check(struct objtool_file *file) | 4808 | int check(struct objtool_file *file) |
| 4796 | { | 4809 | { |
| 4797 | struct disas_context *disas_ctx; | 4810 | struct disas_context *disas_ctx = NULL; |
| 4798 | int ret = 0, warnings = 0; | 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 | arch_initial_func_cfi_state(&initial_func_cfi); | 4823 | arch_initial_func_cfi_state(&initial_func_cfi); |
| 4801 | init_cfi_state(&init_cfi); | 4824 | init_cfi_state(&init_cfi); |
| 4802 | init_cfi_state(&func_cfi); | 4825 | init_cfi_state(&func_cfi); |
| @@ -4936,11 +4959,12 @@ out: · 133 unmodified lines | |||
| 4936 | if (opts.verbose) { | 4959 | if (opts.verbose) { |
| 4937 | if (opts.werror && warnings) | 4960 | if (opts.werror && warnings) |
| 4938 | WARN("%d warning(s) upgraded to errors", warnings); | 4961 | WARN("%d warning(s) upgraded to errors", warnings); |
| 4939 | disas_ctx = disas_context_create(file); | 4962 | disas_warned_funcs(disas_ctx); |
| 4940 | if (disas_ctx) { | 4963 | } |
| 4941 | disas_warned_funcs(disas_ctx); | 4964 | |
| 4942 | disas_context_destroy(disas_ctx); | 4965 | if (disas_ctx) { |
| 4943 | } | 4966 | disas_context_destroy(disas_ctx); |
| 4967 | objtool_disas_ctx = NULL; | ||
| 4944 | } | 4968 | } |
| 4945 | 4969 | ||
| 4946 | free_insns(file); | 4970 | free_insns(file); |
| @@ -303,7 +303,7 @@ void disas_context_destroy(struct disas_context *dctx) · 302 unmodified lines | |||
| 303 | free(dctx); | 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 | return dctx->result; | 308 | return dctx->result; |
| 309 | } | 309 | } |
| @@ -311,8 +311,7 @@ static char *disas_result(struct disas_context *dctx) · 1 unmodified line | |||
| 311 | /* | 311 | /* |
| 312 | * Disassemble a single instruction. Return the size of the instruction. | 312 | * Disassemble a single instruction. Return the size of the instruction. |
| 313 | */ | 313 | */ |
| 314 | static size_t disas_insn(struct disas_context *dctx, | 314 | size_t disas_insn(struct disas_context *dctx, struct instruction *insn) |
| 315 | struct instruction *insn) | ||
| 316 | { | 315 | { |
| 317 | disassembler_ftype disasm = dctx->disassembler; | 316 | disassembler_ftype disasm = dctx->disassembler; |
| 318 | struct disassemble_info *dinfo = &dctx->info; | 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 | insn && insn->offset < sym->offset + sym->len; \ | 141 | insn && insn->offset < sym->offset + sym->len; \ |
| 142 | insn = next_insn_same_sec(file, insn)) | 142 | insn = next_insn_same_sec(file, insn)) |
| 143 | 143 | ||
| 144 | const char *objtool_disas_insn(struct instruction *insn); | ||
| 145 | |||
| 144 | #endif /* _CHECK_H */ | 146 | #endif /* _CHECK_H */ |
| @@ -17,6 +17,8 @@ void disas_warned_funcs(struct disas_context *dctx); · 16 unmodified lines | |||
| 17 | int disas_info_init(struct disassemble_info *dinfo, | 17 | int disas_info_init(struct disassemble_info *dinfo, |
| 18 | int arch, int mach32, int mach64, | 18 | int arch, int mach32, int mach64, |
| 19 | const char *options); | 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 | #else /* DISAS */ | 23 | #else /* DISAS */ |
| 22 | 24 | ||
| @@ -38,6 +40,17 @@ static inline int disas_info_init(struct disassemble_info *dinfo, · 15 unmodified lines | |||
| 38 | return -1; | 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 | #endif /* DISAS */ | 54 | #endif /* DISAS */ |
| 42 | 55 | ||
| 43 | #endif /* _DISAS_H */ | 56 | #endif /* _DISAS_H */ |
| @@ -77,9 +77,11 @@ static inline char *offstr(struct section *sec, unsigned long offset) · 76 unmodified lines | |||
| 77 | #define WARN_INSN(insn, format, ...) \ | 77 | #define WARN_INSN(insn, format, ...) \ |
| 78 | ({ \ | 78 | ({ \ |
| 79 | struct instruction *_insn = (insn); \ | 79 | struct instruction *_insn = (insn); \ |
| 80 | if (!_insn->sym || !_insn->sym->warned) \ | 80 | if (!_insn->sym || !_insn->sym->warned) { \ |
| 81 | WARN_FUNC(_insn->sec, _insn->offset, format, \ | 81 | WARN_FUNC(_insn->sec, _insn->offset, format, \ |
| 82 | ##__VA_ARGS__); \ | 82 | ##__VA_ARGS__); \ |
| 83 | BT_INSN(_insn, ""); \ | ||
| 84 | } \ | ||
| 83 | if (_insn->sym) \ | 85 | if (_insn->sym) \ |
| 84 | _insn->sym->warned = 1; \ | 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 | #define BT_INSN(insn, format, ...) \ | 89 | #define BT_INSN(insn, format, ...) \ |
| 88 | ({ \ | 90 | ({ \ |
| 89 | if (opts.verbose || opts.backtrace) { \ | 91 | if (opts.verbose || opts.backtrace) { \ |
| 90 | struct instruction *_insn = (insn); \ | 92 | struct instruction *__insn = (insn); \ |
| 91 | char *_str = offstr(_insn->sec, _insn->offset); \ | 93 | char *_str = offstr(__insn->sec, __insn->offset); \ |
| 92 | WARN(" %s: " format, _str, ##__VA_ARGS__); \ | 94 | const char *_istr = objtool_disas_insn(__insn); \ |
| 93 | free(_str); \ | 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 | ||