Integrate adding files with the file manager
[anjuta-git-plugin.git] / plugins / valgrind / symtab.c
blobed6e81fec369e971b5fd67288557888cd1ed8465
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
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.
23 // fixme
24 #define LDD_PATH "/usr/bin/ldd"
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
30 #include <glib.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <sys/types.h>
36 #include <unistd.h>
37 #include <fcntl.h>
38 #include <errno.h>
40 #include "symtab.h"
41 #include "process.h"
42 #include "ldd.h"
44 #define d(x)
45 #define w(x) x
47 #define POINTER_ARITHMETIC(POINTER, OFFSET) \
48 (void *)((char *)(POINTER) + (OFFSET))
50 static asymbol **
51 slurp_symtab (bfd *abfd, long *symcount)
53 asymbol **syms = (asymbol **) NULL;
54 long storage;
56 if (!(bfd_get_file_flags (abfd) & HAS_SYMS)) {
57 w(fprintf (stderr, "No symbols in \"%s\".\n", bfd_get_filename (abfd)));
58 *symcount = 0;
59 return NULL;
62 storage = bfd_get_symtab_upper_bound (abfd);
63 if (storage < 0) {
64 w(fprintf (stderr, "%s: Invalid upper-bound\n", bfd_get_filename (abfd)));
65 *symcount = 0;
66 return NULL;
67 } else if (storage == 0) {
68 *symcount = 0;
69 return NULL;
72 syms = g_malloc (storage);
74 *symcount = bfd_canonicalize_symtab (abfd, syms);
76 if (*symcount < 0) {
77 w(fprintf (stderr, "%s: Invalid symbol count\n", bfd_get_filename (abfd)));
78 g_free (syms);
79 return NULL;
82 if (*symcount == 0) {
83 w(fprintf (stderr, "%s: No symbols\n", bfd_get_filename (abfd)));
86 return syms;
89 static SymTabMap *
90 symtab_map_new (const char *filename, const char *libname, void *load_addr)
92 SymTabMap *map;
93 asection *section;
95 map = g_new (SymTabMap, 1);
96 map->next = NULL;
98 map->abfd = bfd_openr (filename, NULL);
99 if (map->abfd == NULL) {
100 g_free (map);
101 return NULL;
104 if (!bfd_check_format (map->abfd, bfd_object)) {
105 bfd_close (map->abfd);
106 g_free (map);
107 return NULL;
110 map->syms = slurp_symtab (map->abfd, &map->symcount);
111 if (!map->syms) {
112 bfd_close (map->abfd);
113 g_free (map);
114 return NULL;
117 section = bfd_get_section_by_name (map->abfd, ".text");
118 if (!section) {
119 g_free (map->syms);
120 bfd_close (map->abfd);
121 g_free (map);
122 return NULL;
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));
129 #else
130 map->text_end = POINTER_ARITHMETIC(map->text_start, bfd_get_section_size (section));
131 #endif
133 map->filename = g_strdup (filename);
134 map->libname = g_strdup (libname);
135 map->load_addr = load_addr;
137 return map;
140 static void
141 load_shared_lib (LddParser *ldd, LddSharedLib *shlib, void *user_data)
143 SymTab *symtab = user_data;
144 SymTabMap *lib;
146 if (!(lib = symtab_map_new ((char *)shlib->path, (char *)shlib->libname, (void *) shlib->addr))) {
147 ldd_shared_lib_free (shlib);
148 return;
151 symtab->tail->next = lib;
152 symtab->tail = lib;
154 ldd_shared_lib_free (shlib);
158 SymTab *
159 symtab_new (const char *filename)
161 const char *basename;
162 SymTab *symtab;
163 LddParser *ldd;
164 char *argv[3];
165 pid_t pid;
166 int fd;
168 symtab = g_new (SymTab, 1);
169 symtab->libs = NULL;
170 symtab->tail = (SymTabMap *) &symtab->libs;
172 if (!(basename = strrchr (filename, '/')))
173 basename = filename;
174 else
175 basename++;
177 if (!(symtab->prog = symtab_map_new (filename, basename, NULL))) {
178 g_free (symtab);
179 return NULL;
182 argv[0] = LDD_PATH;
183 argv[1] = (char *) filename;
184 argv[2] = NULL;
186 if ((pid = process_fork (LDD_PATH, argv, FALSE, -1, NULL, &fd, NULL, NULL)) == -1)
187 return symtab;
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);
195 close (fd);
197 process_wait (pid);
199 symtab->prog->next = symtab->libs;
201 return symtab;
204 static void
205 symtab_map_free (SymTabMap *map)
207 g_free (map->filename);
208 g_free (map->libname);
209 bfd_close (map->abfd);
210 g_free (map->syms);
211 g_free (map);
214 void
215 symtab_free (SymTab *symtab)
217 SymTabMap *n, *nn;
219 if (symtab == NULL)
220 return;
222 symtab_map_free (symtab->prog);
224 n = symtab->libs;
225 while (n != NULL) {
226 nn = n->next;
227 symtab_map_free (n);
228 n = nn;
231 g_free (symtab);
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);
240 static char *
241 demangle (bfd *abfd, const char *name, int demangle_cpp)
243 char *demangled = NULL;
245 if (bfd_get_symbol_leading_char (abfd) == *name)
246 name++;
248 if (demangle_cpp)
249 demangled = cplus_demangle (name, DMGL_PARAMS | DMGL_ANSI);
251 return g_strdup (name);
254 static SymTabMap *
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;
262 while (map) {
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)
267 return prev;
269 map = map->next;
272 return NULL;
275 SymTabSymbol *
276 symtab_resolve_addr (SymTab *symtab, void *addr, int demangle_cpp)
278 SymTabSymbol *sym;
279 const char *name;
280 SymTabMap *lib;
281 bfd_vma offset;
283 if (!(lib = symtab_find_lib (symtab, addr))) {
284 d(fprintf (stderr, "can't figure out which lib %p is in\n", addr));
285 return NULL;
288 if (lib->abfd->iostream == NULL) {
289 lib->abfd->iostream = (void *) fopen (lib->filename, "r+");
290 if (lib->abfd->iostream == NULL)
291 return 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)) {
301 if (name)
302 sym->function = demangle (lib->abfd, name, demangle_cpp);
303 else
304 sym->function = NULL;
305 } else {
306 d(fprintf (stderr, "bfd failed to find symbols for %p\n", addr));
307 g_free (sym);
308 sym = NULL;
311 return sym;
315 void
316 symtab_symbol_free (SymTabSymbol *sym)
318 if (sym == NULL)
319 return;
321 g_free (sym->function);
322 g_free (sym);