1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Authors: Jeffrey Stedfast <fejj@ximian.com>
5 * Copyright 2003 Ximian, Inc. (www.ximian.com)
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 #define LDD_PATH "/usr/bin/ldd"
35 #include <sys/types.h>
47 #define POINTER_ARITHMETIC(POINTER, OFFSET) \
48 (void *)((char *)(POINTER) + (OFFSET))
51 slurp_symtab (bfd
*abfd
, long *symcount
)
53 asymbol
**syms
= (asymbol
**) NULL
;
56 if (!(bfd_get_file_flags (abfd
) & HAS_SYMS
)) {
57 w(fprintf (stderr
, "No symbols in \"%s\".\n", bfd_get_filename (abfd
)));
62 storage
= bfd_get_symtab_upper_bound (abfd
);
64 w(fprintf (stderr
, "%s: Invalid upper-bound\n", bfd_get_filename (abfd
)));
67 } else if (storage
== 0) {
72 syms
= g_malloc (storage
);
74 *symcount
= bfd_canonicalize_symtab (abfd
, syms
);
77 w(fprintf (stderr
, "%s: Invalid symbol count\n", bfd_get_filename (abfd
)));
83 w(fprintf (stderr
, "%s: No symbols\n", bfd_get_filename (abfd
)));
90 symtab_map_new (const char *filename
, const char *libname
, void *load_addr
)
95 map
= g_new (SymTabMap
, 1);
98 map
->abfd
= bfd_openr (filename
, NULL
);
99 if (map
->abfd
== NULL
) {
104 if (!bfd_check_format (map
->abfd
, bfd_object
)) {
105 bfd_close (map
->abfd
);
110 map
->syms
= slurp_symtab (map
->abfd
, &map
->symcount
);
112 bfd_close (map
->abfd
);
117 section
= bfd_get_section_by_name (map
->abfd
, ".text");
120 bfd_close (map
->abfd
);
125 map
->text_section
= section
;
126 map
->text_start
= POINTER_ARITHMETIC(load_addr
, bfd_section_vma (map
->abfd
, section
));
127 #ifdef HAVE_BFD_GET_SECTION_SIZE_BEFORE_RELOC
128 map
->text_end
= POINTER_ARITHMETIC(map
->text_start
, bfd_get_section_size_before_reloc (section
));
130 map
->text_end
= POINTER_ARITHMETIC(map
->text_start
, bfd_get_section_size (section
));
133 map
->filename
= g_strdup (filename
);
134 map
->libname
= g_strdup (libname
);
135 map
->load_addr
= load_addr
;
141 load_shared_lib (LddParser
*ldd
, LddSharedLib
*shlib
, void *user_data
)
143 SymTab
*symtab
= user_data
;
146 if (!(lib
= symtab_map_new ((char *)shlib
->path
, (char *)shlib
->libname
, (void *) shlib
->addr
))) {
147 ldd_shared_lib_free (shlib
);
151 symtab
->tail
->next
= lib
;
154 ldd_shared_lib_free (shlib
);
159 symtab_new (const char *filename
)
161 const char *basename
;
168 symtab
= g_new (SymTab
, 1);
170 symtab
->tail
= (SymTabMap
*) &symtab
->libs
;
172 if (!(basename
= strrchr (filename
, '/')))
177 if (!(symtab
->prog
= symtab_map_new (filename
, basename
, NULL
))) {
183 argv
[1] = (char *) filename
;
186 if ((pid
= process_fork (LDD_PATH
, argv
, FALSE
, -1, NULL
, &fd
, NULL
, NULL
)) == -1)
189 ldd
= ldd_parser_new (fd
, load_shared_lib
, symtab
);
190 while (ldd_parser_step (ldd
) > 0)
193 ldd_parser_flush (ldd
);
194 ldd_parser_free (ldd
);
199 symtab
->prog
->next
= symtab
->libs
;
205 symtab_map_free (SymTabMap
*map
)
207 g_free (map
->filename
);
208 g_free (map
->libname
);
209 bfd_close (map
->abfd
);
215 symtab_free (SymTab
*symtab
)
222 symtab_map_free (symtab
->prog
);
235 #define DMGL_PARAMS (1 << 0) /* Include function args */
236 #define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
238 extern char *cplus_demangle (const char *mangled
, int options
);
241 demangle (bfd
*abfd
, const char *name
, int demangle_cpp
)
243 char *demangled
= NULL
;
245 if (bfd_get_symbol_leading_char (abfd
) == *name
)
249 demangled
= cplus_demangle (name
, DMGL_PARAMS
| DMGL_ANSI
);
251 return g_strdup (name
);
255 symtab_find_lib (SymTab
*symtab
, void *addr
)
257 SymTabMap
*map
, *prev
;
259 d(fprintf (stderr
, "looking for library with symbols for %p\n", addr
));
261 prev
= map
= symtab
->prog
;
263 d(fprintf (stderr
, "%s: load_addr=%p; text_start=%p; text_end=%p\n",
264 map
->libname
, map
->load_addr
, map
->text_start
, map
->text_end
));
266 if (addr
> map
->text_start
&& addr
< map
->text_end
)
276 symtab_resolve_addr (SymTab
*symtab
, void *addr
, int demangle_cpp
)
283 if (!(lib
= symtab_find_lib (symtab
, addr
))) {
284 d(fprintf (stderr
, "can't figure out which lib %p is in\n", addr
));
288 if (lib
->abfd
->iostream
== NULL
) {
289 lib
->abfd
->iostream
= (void *) fopen (lib
->filename
, "r+");
290 if (lib
->abfd
->iostream
== NULL
)
294 sym
= g_new (SymTabSymbol
, 1);
296 offset
= (bfd_vma
)((char *)addr
- (char *)lib
->load_addr
);
298 if (bfd_find_nearest_line (lib
->abfd
, lib
->text_section
, lib
->syms
,
299 offset
- lib
->text_section
->vma
,
300 &sym
->filename
, &name
, &sym
->lineno
)) {
302 sym
->function
= demangle (lib
->abfd
, name
, demangle_cpp
);
304 sym
->function
= NULL
;
306 d(fprintf (stderr
, "bfd failed to find symbols for %p\n", addr
));
316 symtab_symbol_free (SymTabSymbol
*sym
)
321 g_free (sym
->function
);