1 /* Test program for libdwfl basic module tracking, relocation.
2 Copyright (C) 2005, 2007 Red Hat, Inc.
3 This file is part of elfutils.
4
5 This file is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
9
10 elfutils is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
17
18 #include <config.h>
19 #include <assert.h>
20 #include <inttypes.h>
21 #include <sys/types.h>
22 #include <stdio.h>
23 #include <stdio_ext.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <error.h>
27 #include <locale.h>
28 #include <argp.h>
29 #include ELFUTILS_HEADER(dwfl)
30 #include <dwarf.h>
31
32 static bool show_inlines;
33
34 struct info
35 {
36 Dwarf_Die *cudie;
37 Dwarf_Addr dwbias;
38 };
39
40 static int
print_instance(Dwarf_Die * instance,void * arg)41 print_instance (Dwarf_Die *instance, void *arg)
42 {
43 const struct info *info = arg;
44
45 printf (" inlined");
46
47 Dwarf_Files *files;
48 if (dwarf_getsrcfiles (info->cudie, &files, NULL) == 0)
49 {
50 Dwarf_Attribute attr_mem;
51 Dwarf_Word val;
52 if (dwarf_formudata (dwarf_attr (instance, DW_AT_call_file,
53 &attr_mem), &val) == 0)
54 {
55 const char *file = dwarf_filesrc (files, val, NULL, NULL);
56 int lineno = 0, colno = 0;
57 if (dwarf_formudata (dwarf_attr (instance, DW_AT_call_line,
58 &attr_mem), &val) == 0)
59 lineno = val;
60 if (dwarf_formudata (dwarf_attr (instance, DW_AT_call_column,
61 &attr_mem), &val) == 0)
62 colno = val;
63 if (lineno == 0)
64 {
65 if (file != NULL)
66 printf (" from %s", file);
67 }
68 else if (colno == 0)
69 printf (" at %s:%u", file, lineno);
70 else
71 printf (" at %s:%u:%u", file, lineno, colno);
72 }
73 }
74
75 Dwarf_Addr lo = -1, hi = -1, entry = -1;
76 if (dwarf_lowpc (instance, &lo) == 0)
77 lo += info->dwbias;
78 else
79 printf (" (lowpc => %s)", dwarf_errmsg (-1));
80 if (dwarf_highpc (instance, &hi) == 0)
81 hi += info->dwbias;
82 else
83 printf (" (highpc => %s)", dwarf_errmsg (-1));
84
85 Dwarf_Attribute attr_mem;
86 Dwarf_Attribute *attr = dwarf_attr (instance, DW_AT_entry_pc, &attr_mem);
87 if (attr != NULL)
88 {
89 if (dwarf_formaddr (attr, &entry) == 0)
90 entry += info->dwbias;
91 else
92 printf (" (entrypc => %s)", dwarf_errmsg (-1));
93 }
94
95 if (lo != (Dwarf_Addr) -1 || hi != (Dwarf_Addr) -1)
96 printf (" %#" PRIx64 "..%#" PRIx64, lo, hi);
97 if (entry != (Dwarf_Addr) -1)
98 printf (" => %#" PRIx64 "\n", entry);
99 else
100 puts ("");
101
102 return DWARF_CB_OK;
103 }
104
105 static void
print_inline(Dwarf_Die * func,void * arg)106 print_inline (Dwarf_Die *func, void *arg)
107 {
108 if (dwarf_func_inline_instances (func, &print_instance, arg) != 0)
109 printf (" error finding instances: %s\n", dwarf_errmsg (-1));
110 }
111
112 static int
print_func(Dwarf_Die * func,void * arg)113 print_func (Dwarf_Die *func, void *arg)
114 {
115 const struct info *info = arg;
116
117 const char *file = dwarf_decl_file (func);
118 int line = -1;
119 dwarf_decl_line (func, &line);
120 const char *fct = dwarf_diename (func);
121
122 printf (" %s:%d: %s:", file, line, fct);
123
124 if (dwarf_func_inline (func))
125 {
126 puts (" inline function");
127 if (show_inlines)
128 print_inline (func, arg);
129 }
130 else
131 {
132 Dwarf_Addr lo = -1, hi = -1, entry = -1;
133 if (dwarf_lowpc (func, &lo) == 0)
134 lo += info->dwbias;
135 else
136 printf (" (lowpc => %s)", dwarf_errmsg (-1));
137 if (dwarf_highpc (func, &hi) == 0)
138 hi += info->dwbias;
139 else
140 printf (" (highpc => %s)", dwarf_errmsg (-1));
141 if (dwarf_entrypc (func, &entry) == 0)
142 entry += info->dwbias;
143 else
144 printf (" (entrypc => %s)", dwarf_errmsg (-1));
145
146 if (lo != (Dwarf_Addr) -1 || hi != (Dwarf_Addr) -1
147 || entry != (Dwarf_Addr) -1)
148 printf (" %#" PRIx64 "..%#" PRIx64 " => %#" PRIx64 "\n",
149 lo, hi, entry);
150 else
151 puts ("");
152 }
153
154 return DWARF_CB_OK;
155 }
156
157 static int
list_module(Dwfl_Module * mod,void ** userdata,const char * name,Dwarf_Addr base,void * arg)158 list_module (Dwfl_Module *mod __attribute__ ((unused)),
159 void **userdata __attribute__ ((unused)),
160 const char *name, Dwarf_Addr base,
161 void *arg __attribute__ ((unused)))
162 {
163 Dwarf_Addr start;
164 Dwarf_Addr end;
165 const char *file;
166 const char *debug;
167 if (dwfl_module_info (mod, NULL, &start, &end,
168 NULL, NULL, &file, &debug) != name
169 || start != base)
170 abort ();
171 printf ("module: %30s %08" PRIx64 "..%08" PRIx64 " %s %s\n",
172 name, start, end, file, debug);
173 return DWARF_CB_OK;
174 }
175
176 static int
print_module(Dwfl_Module * mod,void ** userdata,const char * name,Dwarf_Addr base,Dwarf * dw,Dwarf_Addr bias,void * arg)177 print_module (Dwfl_Module *mod __attribute__ ((unused)),
178 void **userdata __attribute__ ((unused)),
179 const char *name, Dwarf_Addr base,
180 Dwarf *dw, Dwarf_Addr bias,
181 void *arg)
182 {
183 printf ("module: %30s %08" PRIx64 " %s %" PRIx64 " (%s)\n",
184 name, base, dw == NULL ? "no" : "DWARF", bias, dwfl_errmsg (-1));
185
186 if (dw != NULL && *(const bool *) arg)
187 {
188 Dwarf_Off off = 0;
189 size_t cuhl;
190 Dwarf_Off noff;
191
192 while (dwarf_nextcu (dw, off, &noff, &cuhl, NULL, NULL, NULL) == 0)
193 {
194 Dwarf_Die die_mem;
195 struct info info = { dwarf_offdie (dw, off + cuhl, &die_mem), bias };
196 (void) dwarf_getfuncs (info.cudie, print_func, &info, 0);
197
198 off = noff;
199 }
200 }
201
202 return DWARF_CB_OK;
203 }
204
205 static bool show_functions;
206
207 /* gettext helper macro. */
208 #undef N_
209 #define N_(Str) Str
210
211 static const struct argp_option options[] =
212 {
213 { "functions", 'f', NULL, 0, N_("Additionally show function names"), 0 },
214 { "inlines", 'i', NULL, 0, N_("Show instances of inlined functions"), 0 },
215 { NULL, 0, NULL, 0, NULL, 0 }
216 };
217
218 static error_t
parse_opt(int key,char * arg,struct argp_state * state)219 parse_opt (int key, char *arg __attribute__ ((unused)),
220 struct argp_state *state __attribute__ ((unused)))
221 {
222 switch (key)
223 {
224 case ARGP_KEY_INIT:
225 state->child_inputs[0] = state->input;
226 break;
227
228 case 'f':
229 show_functions = true;
230 break;
231
232 case 'i':
233 show_inlines = show_functions = true;
234 break;
235
236 default:
237 return ARGP_ERR_UNKNOWN;
238 }
239 return 0;
240 }
241
242 int
main(int argc,char ** argv)243 main (int argc, char **argv)
244 {
245 /* We use no threads here which can interfere with handling a stream. */
246 (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER);
247
248 /* Set locale. */
249 (void) setlocale (LC_ALL, "");
250
251 Dwfl *dwfl = NULL;
252 const struct argp_child argp_children[] =
253 {
254 { .argp = dwfl_standard_argp () },
255 { .argp = NULL }
256 };
257 const struct argp argp =
258 {
259 options, parse_opt, NULL, NULL, argp_children, NULL, NULL
260 };
261 (void) argp_parse (&argp, argc, argv, 0, NULL, &dwfl);
262 assert (dwfl != NULL);
263
264 ptrdiff_t p = 0;
265 do
266 p = dwfl_getmodules (dwfl, &list_module, NULL, p);
267 while (p > 0);
268 if (p < 0)
269 error (2, 0, "dwfl_getmodules: %s", dwfl_errmsg (-1));
270
271 do
272 p = dwfl_getdwarf (dwfl, &print_module, &show_functions, p);
273 while (p > 0);
274 if (p < 0)
275 error (2, 0, "dwfl_getdwarf: %s", dwfl_errmsg (-1));
276
277 p = 0;
278 do
279 p = dwfl_getmodules (dwfl, &list_module, NULL, p);
280 while (p > 0);
281 if (p < 0)
282 error (2, 0, "dwfl_getmodules: %s", dwfl_errmsg (-1));
283
284 dwfl_end (dwfl);
285
286 return 0;
287 }
288