1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 /* 3 * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com> 4 */ 5 6 #ifndef _WARN_H 7 #define _WARN_H 8 9 #include <stdlib.h> 10 #include <string.h> 11 #include <sys/types.h> 12 #include <sys/stat.h> 13 #include <fcntl.h> 14 #include <errno.h> 15 #include <objtool/builtin.h> 16 #include <objtool/elf.h> 17 18 extern const char *objname; 19 20 static inline char *offstr(struct section *sec, unsigned long offset) 21 { 22 bool is_text = (sec->sh.sh_flags & SHF_EXECINSTR); 23 struct symbol *sym = NULL; 24 char *str; 25 int len; 26 27 if (is_text) 28 sym = find_func_containing(sec, offset); 29 if (!sym) 30 sym = find_symbol_containing(sec, offset); 31 32 if (sym) { 33 str = malloc(strlen(sym->name) + strlen(sec->name) + 40); 34 len = sprintf(str, "%s+0x%lx", sym->name, offset - sym->offset); 35 if (opts.sec_address) 36 sprintf(str+len, " (%s+0x%lx)", sec->name, offset); 37 } else { 38 str = malloc(strlen(sec->name) + 20); 39 sprintf(str, "%s+0x%lx", sec->name, offset); 40 } 41 42 return str; 43 } 44 45 #define ___WARN(severity, extra, format, ...) \ 46 fprintf(stderr, \ 47 "%s%s%s: objtool" extra ": " format "\n", \ 48 objname ?: "", \ 49 objname ? ": " : "", \ 50 severity, \ 51 ##__VA_ARGS__) 52 53 #define __WARN(severity, format, ...) \ 54 ___WARN(severity, "", format, ##__VA_ARGS__) 55 56 #define __WARN_LINE(severity, format, ...) \ 57 ___WARN(severity, " [%s:%d]", format, __FILE__, __LINE__, ##__VA_ARGS__) 58 59 #define __WARN_ELF(severity, format, ...) \ 60 __WARN_LINE(severity, "%s: " format " failed: %s", __func__, ##__VA_ARGS__, elf_errmsg(-1)) 61 62 #define __WARN_GLIBC(severity, format, ...) \ 63 __WARN_LINE(severity, "%s: " format " failed: %s", __func__, ##__VA_ARGS__, strerror(errno)) 64 65 #define __WARN_FUNC(severity, sec, offset, format, ...) \ 66 ({ \ 67 char *_str = offstr(sec, offset); \ 68 __WARN(severity, "%s: " format, _str, ##__VA_ARGS__); \ 69 free(_str); \ 70 }) 71 72 #define WARN_STR (opts.werror ? "error" : "warning") 73 74 #define WARN(format, ...) __WARN(WARN_STR, format, ##__VA_ARGS__) 75 #define WARN_FUNC(sec, offset, format, ...) __WARN_FUNC(WARN_STR, sec, offset, format, ##__VA_ARGS__) 76 77 #define WARN_INSN(insn, format, ...) \ 78 ({ \ 79 struct instruction *_insn = (insn); \ 80 if (!_insn->sym || !_insn->sym->warned) { \ 81 WARN_FUNC(_insn->sec, _insn->offset, format, \ 82 ##__VA_ARGS__); \ 83 BT_INSN(_insn, ""); \ 84 } \ 85 if (_insn->sym) \ 86 _insn->sym->warned = 1; \ 87 }) 88 89 #define BT_INSN(insn, format, ...) \ 90 ({ \ 91 if (opts.verbose || opts.backtrace) { \ 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); \ 100 __insn->trace = 1; \ 101 } \ 102 }) 103 104 #define ERROR_STR "error" 105 106 #define ERROR(format, ...) __WARN(ERROR_STR, format, ##__VA_ARGS__) 107 #define ERROR_ELF(format, ...) __WARN_ELF(ERROR_STR, format, ##__VA_ARGS__) 108 #define ERROR_GLIBC(format, ...) __WARN_GLIBC(ERROR_STR, format, ##__VA_ARGS__) 109 #define ERROR_FUNC(sec, offset, format, ...) __WARN_FUNC(ERROR_STR, sec, offset, format, ##__VA_ARGS__) 110 #define ERROR_INSN(insn, format, ...) ERROR_FUNC(insn->sec, insn->offset, format, ##__VA_ARGS__) 111 112 extern bool debug; 113 extern int indent; 114 115 static inline void unindent(int *unused) { indent--; } 116 117 /* 118 * Clang prior to 17 is being silly and considers many __cleanup() variables 119 * as unused (because they are, their sole purpose is to go out of scope). 120 * 121 * https://github.com/llvm/llvm-project/commit/877210faa447f4cc7db87812f8ed80e398fedd61 122 */ 123 #undef __cleanup 124 #define __cleanup(func) __maybe_unused __attribute__((__cleanup__(func))) 125 126 #define __dbg(format, ...) \ 127 fprintf(stderr, \ 128 "DEBUG: %s%s" format "\n", \ 129 objname ?: "", \ 130 objname ? ": " : "", \ 131 ##__VA_ARGS__) 132 133 #define dbg(args...) \ 134 ({ \ 135 if (unlikely(debug)) \ 136 __dbg(args); \ 137 }) 138 139 #define __dbg_indent(format, ...) \ 140 ({ \ 141 if (unlikely(debug)) \ 142 __dbg("%*s" format, indent * 8, "", ##__VA_ARGS__); \ 143 }) 144 145 #define dbg_indent(args...) \ 146 int __cleanup(unindent) __dummy_##__COUNTER__; \ 147 __dbg_indent(args); \ 148 indent++ 149 150 #define dbg_checksum(func, insn, checksum) \ 151 ({ \ 152 if (unlikely(insn->sym && insn->sym->pfunc && \ 153 insn->sym->pfunc->debug_checksum)) { \ 154 char *insn_off = offstr(insn->sec, insn->offset); \ 155 __dbg("checksum: %s %s %016llx", \ 156 func->name, insn_off, (unsigned long long)checksum);\ 157 free(insn_off); \ 158 } \ 159 }) 160 161 #endif /* _WARN_H */ 162