xref: /linux/tools/objtool/disas.c (revision 1013f2e37bec39b1df5679e1c1e2572ece87c088)
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