blob: 60fcdf639a7659fa5b9ca84a1f7fd2b1074d0fac [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>
Roland McGrathce4550a2005-08-10 08:10:07 +000024#include <gelf.h>
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000025#include <inttypes.h>
Roland McGrathce4550a2005-08-10 08:10:07 +000026#include <libdw.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{
Roland McGrathce4550a2005-08-10 08:10:07 +000052 { NULL, 0, NULL, 0, N_("Input Selection:"), 0 },
53 { "exe", 'e', "FILE", 0, N_("Find addresses in FILE"), 0 },
54
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000055 { NULL, 0, NULL, 0, N_("Output Selection:"), 0 },
56 { "basenames", 's', NULL, 0, N_("Show only base names of source files"), 0 },
57 { "functions", 'f', NULL, 0, N_("Additional show function names"), 0 },
58
59 { NULL, 0, NULL, 0, N_("Miscellaneous:"), 0 },
60 /* Unsupported options. */
61 { "target", 'b', "ARG", OPTION_HIDDEN, NULL, 0 },
62 { "demangle", 'C', "ARG", OPTION_HIDDEN | OPTION_ARG_OPTIONAL, NULL, 0 },
63 { "demangler", OPT_DEMANGLER, "ARG", OPTION_HIDDEN, NULL, 0 },
64 { NULL, 0, NULL, 0, NULL, 0 }
65};
66
67/* Short description of program. */
68static const char doc[] = N_("\
69Locate source files and line information for ADDRs (in a.out by default).");
70
71/* Strings for arguments in help texts. */
72static const char args_doc[] = N_("[ADDR...]");
73
74/* Prototype for option handler. */
75static error_t parse_opt (int key, char *arg, struct argp_state *state);
76
77/* Data structure to communicate with argp functions. */
Roland McGrathce4550a2005-08-10 08:10:07 +000078static struct argp argp =
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000079{
Roland McGrathce4550a2005-08-10 08:10:07 +000080 options, parse_opt, args_doc, doc, NULL, NULL, NULL
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000081};
82
83
84/* Handle ADDR. */
Roland McGrathce4550a2005-08-10 08:10:07 +000085static void handle_address (GElf_Addr addr, Elf *elf, Dwarf *dw);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000086
87
Roland McGrathce4550a2005-08-10 08:10:07 +000088/* Name of the executable. */
89static const char *executable = "a.out";
90
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000091/* True if only base names of files should be shown. */
92static bool only_basenames;
93
94/* True if function names should be shown. */
95static bool show_functions;
96
97
98int
99main (int argc, char *argv[])
100{
101 int remaining;
102 int result = 0;
103
104 /* Make memory leak detection possible. */
105 mtrace ();
106
107 /* We use no threads here which can interfere with handling a stream. */
108 (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER);
109
110 /* Set locale. */
111 (void) setlocale (LC_ALL, "");
112
113 /* Make sure the message catalog can be found. */
114 (void) bindtextdomain (PACKAGE, LOCALEDIR);
115
116 /* Initialize the message catalog. */
117 (void) textdomain (PACKAGE);
118
Roland McGrathce4550a2005-08-10 08:10:07 +0000119 /* Parse and process arguments. */
120 (void) argp_parse (&argp, argc, argv, 0, &remaining, NULL);
121
122 /* Tell the library which version we are expecting. */
123 elf_version (EV_CURRENT);
124
125 /* Open the file. */
126 int fd = open64 (executable, O_RDONLY);
127 if (fd == -1)
128 error (1, errno, gettext ("cannot open '%s'"), executable);
129
130 /* Create the ELF descriptor. */
131 Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
132 if (elf == NULL)
133 {
134 close (fd);
135 error (1, 0, gettext ("cannot create ELF descriptor: %s"),
136 elf_errmsg (-1));
137 }
138
139 /* Try to get a DWARF descriptor. If it fails, we try to locate the
140 debuginfo file. */
141 Dwarf *dw = dwarf_begin_elf (elf, DWARF_C_READ, NULL);
142 int fd2 = -1;
143 Elf *elf2 = NULL;
144 if (dw == NULL)
145 {
146 char *canon = canonicalize_file_name (executable);
147 GElf_Ehdr ehdr_mem;
148 GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
149
150 if (canon != NULL && ehdr != NULL)
151 {
152 const char *debuginfo_dir;
153 if (ehdr->e_ident[EI_CLASS] == ELFCLASS32
154 || ehdr->e_machine == EM_IA_64 || ehdr->e_machine == EM_ALPHA)
155 debuginfo_dir = "/usr/lib/debug";
156 else
157 debuginfo_dir = "/usr/lib64/debug";
158
159 char *difname = alloca (strlen (debuginfo_dir) + strlen (canon) + 1);
160 strcpy (stpcpy (difname, debuginfo_dir), canon);
161 fd2 = open64 (difname, O_RDONLY);
162 if (fd2 != -1)
163 dw = dwarf_begin_elf (elf2, DWARF_C_READ, NULL);
164 }
165
166 free (canon);
167 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000168
169 /* Now handle the addresses. In case none are given on the command
170 line, read from stdin. */
171 if (remaining == argc)
172 {
173 /* We use no threads here which can interfere with handling a stream. */
174 (void) __fsetlocking (stdin, FSETLOCKING_BYCALLER);
175
176 char *buf = NULL;
177 size_t len = 0;
178 while (!feof_unlocked (stdin))
179 {
180 if (getline (&buf, &len, stdin) < 0)
181 break;
182
183 char *endp;
184 uintmax_t addr = strtoumax (buf, &endp, 0);
185 if (endp != buf)
Roland McGrathce4550a2005-08-10 08:10:07 +0000186 handle_address (addr, elf2 ?: elf, dw);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000187 else
188 result = 1;
189 }
190
191 free (buf);
192 }
193 else
194 {
195 do
196 {
197 char *endp;
198 uintmax_t addr = strtoumax (argv[remaining], &endp, 0);
199 if (endp != argv[remaining])
Roland McGrathce4550a2005-08-10 08:10:07 +0000200 handle_address (addr, elf2 ?: elf, dw);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000201 else
202 result = 1;
203 }
204 while (++remaining < argc);
205 }
206
207 return result;
208}
209
210
211/* Print the version information. */
212static void
213print_version (FILE *stream, struct argp_state *state __attribute__ ((unused)))
214{
215 fprintf (stream, "addr2line (%s) %s\n", PACKAGE_NAME, VERSION);
216 fprintf (stream, gettext ("\
217Copyright (C) %s Red Hat, Inc.\n\
218This is free software; see the source for copying conditions. There is NO\n\
219warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
220"), "2005");
221 fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
222}
223
224
225/* Handle program arguments. */
226static error_t
Roland McGrathce4550a2005-08-10 08:10:07 +0000227parse_opt (int key, char *arg,
228 struct argp_state *state __attribute__ ((unused)))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000229{
230 switch (key)
231 {
232 case 'b':
233 case 'C':
234 case OPT_DEMANGLER:
235 /* Ignored for compatibility. */
236 break;
237
Roland McGrathce4550a2005-08-10 08:10:07 +0000238 case 'e':
239 executable = arg;
240 break;
241
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000242 case 's':
243 only_basenames = true;
244 break;
245
246 case 'f':
247 show_functions = true;
248 break;
249
250 default:
251 return ARGP_ERR_UNKNOWN;
252 }
253 return 0;
254}
255
256
Roland McGrathce4550a2005-08-10 08:10:07 +0000257struct func_arg
258{
259 GElf_Addr addr;
260 const char *name;
261};
262
263
264static int
265match_func (Dwarf_Func *func, void *arg)
266{
267 struct func_arg *func_arg = (struct func_arg *) arg;
268 Dwarf_Addr addr;
269
270 if (dwarf_func_lowpc (func, &addr) == 0 && addr <= func_arg->addr
271 && dwarf_func_highpc (func, &addr) == 0 && func_arg->addr < addr)
272 {
273 func_arg->name = dwarf_func_name (func);
274 return DWARF_CB_ABORT;
275 }
276
277 return DWARF_CB_OK;
278}
279
280
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000281static const char *
Roland McGrathce4550a2005-08-10 08:10:07 +0000282elf_getname (GElf_Addr addr, Elf *elf)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000283{
Roland McGrathce4550a2005-08-10 08:10:07 +0000284 /* The DWARF information is not available. Use the ELF
285 symbol table. */
286 Elf_Scn *scn = NULL;
287 Elf_Scn *dynscn = NULL;
288
289 while ((scn = elf_nextscn (elf, scn)) != NULL)
290 {
291 GElf_Shdr shdr_mem;
292 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
293 if (shdr != NULL)
294 {
295 if (shdr->sh_type == SHT_SYMTAB)
296 break;
297 if (shdr->sh_type == SHT_DYNSYM)
298 dynscn = scn;
299 }
300 }
301 if (scn == NULL)
302 scn = dynscn;
303
304 if (scn != NULL)
305 {
306 /* Look through the symbol table for a matching symbol. */
307 GElf_Shdr shdr_mem;
308 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
309 assert (shdr != NULL);
310
311 Elf_Data *data = elf_getdata (scn, NULL);
312 if (data != NULL)
313 for (int cnt = 1; cnt < (int) (shdr->sh_size / shdr->sh_entsize);
314 ++cnt)
315 {
316 GElf_Sym sym_mem;
317 GElf_Sym *sym = gelf_getsym (data, cnt, &sym_mem);
318 if (sym != NULL
319 && sym->st_value <= addr
320 && addr < sym->st_value + sym->st_size)
321 return elf_strptr (elf, shdr->sh_link, sym->st_name);
322 }
323 }
324
325 return NULL;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000326}
327
328
329static void
Roland McGrathce4550a2005-08-10 08:10:07 +0000330handle_address (GElf_Addr addr, Elf *elf, Dwarf *dw)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000331{
Roland McGrathce4550a2005-08-10 08:10:07 +0000332 Dwarf_Die die_mem;
333 Dwarf_Die *die = dwarf_addrdie (dw, addr, &die_mem);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000334
335 if (show_functions)
336 {
337 /* First determine the function name. Use the DWARF information if
338 possible. */
Roland McGrathce4550a2005-08-10 08:10:07 +0000339 struct func_arg arg;
340 arg.addr = addr;
341 arg.name = NULL;
342
343 if (dwarf_getfuncs (die, match_func, &arg, 0) <= 0)
344 arg.name = elf_getname (addr, elf);
345
346 puts (arg.name ?: "??");
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000347 }
348
349
Roland McGrathce4550a2005-08-10 08:10:07 +0000350 Dwarf_Line *line;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000351 const char *src;
Roland McGrathce4550a2005-08-10 08:10:07 +0000352 if ((line = dwarf_getsrc_die (die, addr)) != NULL
353 && (src = dwarf_linesrc (line, NULL, NULL)) != NULL)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000354 {
355 if (only_basenames)
356 src = basename (src);
357
Roland McGrathce4550a2005-08-10 08:10:07 +0000358 int lineno;
359 if (dwarf_lineno (line, &lineno) != -1)
360 {
361 int linecol;
362 if (dwarf_linecol (line, &linecol) != -1 && linecol != 0)
363 printf ("%s:%d:%d\n", src, lineno, linecol);
364 else
365 printf ("%s:%d\n", src, lineno);
366 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000367 else
Roland McGrathce4550a2005-08-10 08:10:07 +0000368 printf ("%s:0\n", src);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000369 }
370 else
371 puts ("??:0");
372}