blob: 97eaed10cb584e4608496381326130964074b5e1 [file] [log] [blame]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001/* Locate source files and line information for given addresses
2 Copyright (C) 2005 Red Hat, Inc.
3 Written by Ulrich Drepper <drepper@redhat.com>, 2005.
4
5 This program is Open Source software; you can redistribute it and/or
6 modify it under the terms of the Open Software License version 1.0 as
7 published by the Open Source Initiative.
8
9 You should have received a copy of the Open Software License along
10 with this program; if not, you may obtain a copy of the Open Software
11 License version 1.0 from http://www.opensource.org/licenses/osl.php or
12 by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
13 3001 King Ranch Road, Ukiah, CA 95482. */
14
15#ifdef HAVE_CONFIG_H
16# include <config.h>
17#endif
18
19#include <argp.h>
20#include <assert.h>
21#include <errno.h>
22#include <error.h>
23#include <fcntl.h>
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000024#include <inttypes.h>
Roland McGrath1c83bf12005-08-11 07:03:55 +000025#include <libdwfl.h>
26#include <dwarf.h>
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000027#include <libintl.h>
28#include <locale.h>
29#include <mcheck.h>
30#include <stdbool.h>
31#include <stdio.h>
32#include <stdio_ext.h>
33#include <stdlib.h>
34#include <string.h>
35#include <unistd.h>
36
37
38/* Name and version of program. */
39static void print_version (FILE *stream, struct argp_state *state);
40void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
41
42/* Bug report address. */
43const char *argp_program_bug_address = PACKAGE_BUGREPORT;
44
45
46/* Values for the parameters which have no short form. */
47#define OPT_DEMANGLER 0x100
48
49/* Definitions of arguments for argp functions. */
50static const struct argp_option options[] =
51{
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000052 { NULL, 0, NULL, 0, N_("Output Selection:"), 0 },
53 { "basenames", 's', NULL, 0, N_("Show only base names of source files"), 0 },
54 { "functions", 'f', NULL, 0, N_("Additional show function names"), 0 },
55
56 { NULL, 0, NULL, 0, N_("Miscellaneous:"), 0 },
57 /* Unsupported options. */
58 { "target", 'b', "ARG", OPTION_HIDDEN, NULL, 0 },
59 { "demangle", 'C', "ARG", OPTION_HIDDEN | OPTION_ARG_OPTIONAL, NULL, 0 },
60 { "demangler", OPT_DEMANGLER, "ARG", OPTION_HIDDEN, NULL, 0 },
61 { NULL, 0, NULL, 0, NULL, 0 }
62};
63
64/* Short description of program. */
65static const char doc[] = N_("\
66Locate source files and line information for ADDRs (in a.out by default).");
67
68/* Strings for arguments in help texts. */
69static const char args_doc[] = N_("[ADDR...]");
70
71/* Prototype for option handler. */
72static error_t parse_opt (int key, char *arg, struct argp_state *state);
73
Roland McGrath1c83bf12005-08-11 07:03:55 +000074static struct argp_child argp_children[2]; /* [0] is set in main. */
75
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000076/* Data structure to communicate with argp functions. */
Roland McGrath1c83bf12005-08-11 07:03:55 +000077static const struct argp argp =
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000078{
Roland McGrath1c83bf12005-08-11 07:03:55 +000079 options, parse_opt, args_doc, doc, argp_children, NULL, NULL
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000080};
81
82
83/* Handle ADDR. */
Roland McGrath1c83bf12005-08-11 07:03:55 +000084static void handle_address (GElf_Addr addr, Dwfl *dwfl);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000085
86
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000087/* True if only base names of files should be shown. */
88static bool only_basenames;
89
90/* True if function names should be shown. */
91static bool show_functions;
92
93
94int
95main (int argc, char *argv[])
96{
97 int remaining;
98 int result = 0;
99
100 /* Make memory leak detection possible. */
101 mtrace ();
102
103 /* We use no threads here which can interfere with handling a stream. */
104 (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER);
105
106 /* Set locale. */
107 (void) setlocale (LC_ALL, "");
108
109 /* Make sure the message catalog can be found. */
110 (void) bindtextdomain (PACKAGE, LOCALEDIR);
111
112 /* Initialize the message catalog. */
113 (void) textdomain (PACKAGE);
114
Roland McGrath1c83bf12005-08-11 07:03:55 +0000115 /* Parse and process arguments. This includes opening the modules. */
116 argp_children[0].argp = dwfl_standard_argp ();
117 Dwfl *dwfl = NULL;
118 (void) argp_parse (&argp, argc, argv, 0, &remaining, &dwfl);
119 assert (dwfl != NULL);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000120
121 /* Now handle the addresses. In case none are given on the command
122 line, read from stdin. */
123 if (remaining == argc)
124 {
125 /* We use no threads here which can interfere with handling a stream. */
126 (void) __fsetlocking (stdin, FSETLOCKING_BYCALLER);
127
128 char *buf = NULL;
129 size_t len = 0;
130 while (!feof_unlocked (stdin))
131 {
132 if (getline (&buf, &len, stdin) < 0)
133 break;
134
135 char *endp;
136 uintmax_t addr = strtoumax (buf, &endp, 0);
137 if (endp != buf)
Roland McGrath1c83bf12005-08-11 07:03:55 +0000138 handle_address (addr, dwfl);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000139 else
140 result = 1;
141 }
142
143 free (buf);
144 }
145 else
146 {
147 do
148 {
149 char *endp;
150 uintmax_t addr = strtoumax (argv[remaining], &endp, 0);
151 if (endp != argv[remaining])
Roland McGrath1c83bf12005-08-11 07:03:55 +0000152 handle_address (addr, dwfl);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000153 else
154 result = 1;
155 }
156 while (++remaining < argc);
157 }
158
159 return result;
160}
161
162
163/* Print the version information. */
164static void
165print_version (FILE *stream, struct argp_state *state __attribute__ ((unused)))
166{
167 fprintf (stream, "addr2line (%s) %s\n", PACKAGE_NAME, VERSION);
168 fprintf (stream, gettext ("\
169Copyright (C) %s Red Hat, Inc.\n\
170This is free software; see the source for copying conditions. There is NO\n\
171warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
172"), "2005");
173 fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
174}
175
176
177/* Handle program arguments. */
178static error_t
Roland McGrath1c83bf12005-08-11 07:03:55 +0000179parse_opt (int key, char *arg __attribute__ ((unused)),
180 struct argp_state *state)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000181{
182 switch (key)
183 {
Roland McGrath1c83bf12005-08-11 07:03:55 +0000184 case ARGP_KEY_INIT:
185 state->child_inputs[0] = state->input;
186 break;
187
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000188 case 'b':
189 case 'C':
190 case OPT_DEMANGLER:
191 /* Ignored for compatibility. */
192 break;
193
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000194 case 's':
195 only_basenames = true;
196 break;
197
198 case 'f':
199 show_functions = true;
200 break;
201
202 default:
203 return ARGP_ERR_UNKNOWN;
204 }
205 return 0;
206}
207
208
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000209static const char *
Roland McGrath1c83bf12005-08-11 07:03:55 +0000210dwarf_diename_integrate (Dwarf_Die *die)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000211{
Roland McGrath1c83bf12005-08-11 07:03:55 +0000212 Dwarf_Attribute attr_mem;
213 return dwarf_formstring (dwarf_attr_integrate (die, DW_AT_name, &attr_mem));
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000214}
215
Roland McGrath1c83bf12005-08-11 07:03:55 +0000216static bool
217print_dwarf_function (Dwfl_Module *mod, Dwarf_Addr addr)
218{
219 Dwarf_Addr bias = 0;
220 Dwarf_Die *cudie = dwfl_module_addrdie (mod, addr, &bias);
221
222 Dwarf_Die *scopes;
223 int nscopes = dwarf_getscopes (cudie, addr - bias, &scopes);
224 if (nscopes <= 0)
225 return false;
226
227 for (int i = 0; i < nscopes; ++i)
228 switch (dwarf_tag (&scopes[i]))
229 {
230 case DW_TAG_subprogram:
231 {
232 const char *name = dwarf_diename_integrate (&scopes[i]);
233 if (name == NULL)
234 return false;
235 puts (name);
236 return true;
237 }
238
239 case DW_TAG_inlined_subroutine:
240 {
241 const char *name = dwarf_diename_integrate (&scopes[i]);
242 if (name == NULL)
243 return false;
244 printf ("%s inlined", name);
245
246 Dwarf_Files *files;
247 if (dwarf_getsrcfiles (cudie, &files, NULL) == 0)
248 {
249 Dwarf_Attribute attr_mem;
250 Dwarf_Word val;
251 if (dwarf_formudata (dwarf_attr (&scopes[i],
252 DW_AT_call_file,
253 &attr_mem), &val) == 0)
254 {
255 const char *file = dwarf_filesrc (files, val, NULL, NULL);
256 int lineno = 0, colno = 0;
257 if (dwarf_formudata (dwarf_attr (&scopes[i],
258 DW_AT_call_line,
259 &attr_mem), &val) == 0)
260 lineno = val;
261 if (dwarf_formudata (dwarf_attr (&scopes[i],
262 DW_AT_call_column,
263 &attr_mem), &val) == 0)
264 colno = val;
265 if (lineno == 0)
266 {
267 if (file != NULL)
268 printf (" from %s", file);
269 }
270 else if (colno == 0)
271 printf (" at %s:%u", file, lineno);
272 else
273 printf (" at %s:%u:%u", file, lineno, colno);
274 }
275 }
276 printf (" in ");
277 continue;
278 }
279 }
280
281 return false;
282}
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000283
284static void
Roland McGrath1c83bf12005-08-11 07:03:55 +0000285handle_address (GElf_Addr addr, Dwfl *dwfl)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000286{
Roland McGrath1c83bf12005-08-11 07:03:55 +0000287 Dwfl_Module *mod = dwfl_addrmodule (dwfl, addr);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000288
289 if (show_functions)
290 {
291 /* First determine the function name. Use the DWARF information if
292 possible. */
Roland McGrath1c83bf12005-08-11 07:03:55 +0000293 if (! print_dwarf_function (mod, addr))
294 puts (dwfl_module_addrname (mod, addr) ?: "??");
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000295 }
296
Roland McGrath1c83bf12005-08-11 07:03:55 +0000297 Dwfl_Line *line = dwfl_module_getsrc (mod, addr);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000298
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000299 const char *src;
Roland McGrath1c83bf12005-08-11 07:03:55 +0000300 int lineno, linecol;
301 if (line != NULL && (src = dwfl_lineinfo (line, &addr, &lineno, &linecol,
302 NULL, NULL)) != NULL)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000303 {
304 if (only_basenames)
305 src = basename (src);
306
Roland McGrath1c83bf12005-08-11 07:03:55 +0000307 if (linecol != 0)
308 printf ("%s:%d:%d\n", src, lineno, linecol);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000309 else
Roland McGrath1c83bf12005-08-11 07:03:55 +0000310 printf ("%s:%d\n", src, lineno);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000311 }
312 else
313 puts ("??:0");
314}