1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (C) 2015-2017 Josh Poimboeuf <jpoimboe@redhat.com> 4 */ 5 6 #include <objtool/arch.h> 7 #include <objtool/disas.h> 8 #include <objtool/warn.h> 9 10 #include <linux/string.h> 11 12 struct disas_context { 13 struct objtool_file *file; 14 }; 15 16 struct disas_context *disas_context_create(struct objtool_file *file) 17 { 18 struct disas_context *dctx; 19 20 dctx = malloc(sizeof(*dctx)); 21 if (!dctx) { 22 WARN("failed to allocate disassembly context"); 23 return NULL; 24 } 25 26 dctx->file = file; 27 28 return dctx; 29 } 30 31 void disas_context_destroy(struct disas_context *dctx) 32 { 33 free(dctx); 34 } 35 36 /* 'funcs' is a space-separated list of function names */ 37 static void disas_funcs(const char *funcs) 38 { 39 const char *objdump_str, *cross_compile; 40 int size, ret; 41 char *cmd; 42 43 cross_compile = getenv("CROSS_COMPILE"); 44 if (!cross_compile) 45 cross_compile = ""; 46 47 objdump_str = "%sobjdump -wdr %s | gawk -M -v _funcs='%s' '" 48 "BEGIN { split(_funcs, funcs); }" 49 "/^$/ { func_match = 0; }" 50 "/<.*>:/ { " 51 "f = gensub(/.*<(.*)>:/, \"\\\\1\", 1);" 52 "for (i in funcs) {" 53 "if (funcs[i] == f) {" 54 "func_match = 1;" 55 "base = strtonum(\"0x\" $1);" 56 "break;" 57 "}" 58 "}" 59 "}" 60 "{" 61 "if (func_match) {" 62 "addr = strtonum(\"0x\" $1);" 63 "printf(\"%%04x \", addr - base);" 64 "print;" 65 "}" 66 "}' 1>&2"; 67 68 /* fake snprintf() to calculate the size */ 69 size = snprintf(NULL, 0, objdump_str, cross_compile, objname, funcs) + 1; 70 if (size <= 0) { 71 WARN("objdump string size calculation failed"); 72 return; 73 } 74 75 cmd = malloc(size); 76 77 /* real snprintf() */ 78 snprintf(cmd, size, objdump_str, cross_compile, objname, funcs); 79 ret = system(cmd); 80 if (ret) { 81 WARN("disassembly failed: %d", ret); 82 return; 83 } 84 } 85 86 void disas_warned_funcs(struct disas_context *dctx) 87 { 88 struct symbol *sym; 89 char *funcs = NULL, *tmp; 90 91 if (!dctx) 92 return; 93 94 for_each_sym(dctx->file->elf, sym) { 95 if (sym->warned) { 96 if (!funcs) { 97 funcs = malloc(strlen(sym->name) + 1); 98 if (!funcs) { 99 ERROR_GLIBC("malloc"); 100 return; 101 } 102 strcpy(funcs, sym->name); 103 } else { 104 tmp = malloc(strlen(funcs) + strlen(sym->name) + 2); 105 if (!tmp) { 106 ERROR_GLIBC("malloc"); 107 return; 108 } 109 sprintf(tmp, "%s %s", funcs, sym->name); 110 free(funcs); 111 funcs = tmp; 112 } 113 } 114 } 115 116 if (funcs) 117 disas_funcs(funcs); 118 } 119