1 /* MemProf -- memory profiler and leak detector
2 * Copyright 1999, 2000, 2001, Red Hat, Inc.
3 * Copyright 2002, Kristian Rietveld
5 * Sysprof -- Sampling, systemwide CPU profiler
6 * Copyright 2004, 2005, 2006, 2007, Soeren Sandmann
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 /* Most interesting code in this file is lifted from bfdutils.c
24 * and process.c from Memprof,
34 #include <sys/types.h>
38 #include "elfparser.h"
49 char * undefined_name
;
58 get_inode (const char *filename
)
62 if (strcmp (filename
, "[vdso]") == 0)
65 if (stat (filename
, &statbuf
) < 0)
68 return statbuf
.st_ino
;
72 already_warned (const char *name
)
74 static GPtrArray
*warnings
;
78 warnings
= g_ptr_array_new ();
80 for (i
= 0; i
< warnings
->len
; ++i
)
82 if (strcmp (warnings
->pdata
[i
], name
) == 0)
86 g_ptr_array_add (warnings
, g_strdup (name
));
92 separate_debug_file_exists (const char *name
, guint32 crc
)
95 ElfParser
*parser
= elf_parser_new (name
, NULL
);
98 g_print (" trying %s: ", name
);
108 file_crc
= elf_parser_get_crc32 (parser
);
112 if (!already_warned (name
))
113 g_print ("warning: %s has wrong crc \n", name
);
115 elf_parser_free (parser
);
127 static const char *const debug_file_directory
= DEBUGDIR
;
130 get_debug_file (ElfParser
*elf
,
131 const char *filename
,
135 const char *basename
;
138 char *tries
[N_TRIES
];
145 basename
= elf_parser_get_debug_link (elf
, &crc32
);
148 g_print (" debug link for %s is %s\n", filename
, basename
);
154 dir
= g_path_get_dirname (filename
);
156 tries
[0] = g_build_filename (dir
, basename
, NULL
);
157 tries
[1] = g_build_filename (dir
, ".debug", basename
, NULL
);
158 tries
[2] = g_build_filename ("/usr", "lib", "debug", dir
, basename
, NULL
);
159 tries
[3] = g_build_filename (debug_file_directory
, dir
, basename
, NULL
);
161 for (i
= 0; i
< N_TRIES
; ++i
)
164 g_print ("trying: %s\n", tries
[i
]);
166 result
= separate_debug_file_exists (tries
[i
], crc32
);
170 g_print (" found debug binary for %s: %s\n", filename
, tries
[i
]);
173 *new_name
= g_strdup (tries
[i
]);
180 for (i
= 0; i
< N_TRIES
; ++i
)
187 list_contains_name (GList
*names
, const char *name
)
190 for (list
= names
; list
!= NULL
; list
= list
->next
)
192 const char *n
= list
->data
;
194 if (strcmp (n
, name
) == 0)
202 find_separate_debug_file (ElfParser
*elf
,
203 const char *filename
)
206 char *debug_name
= NULL
;
208 GList
*seen_names
= NULL
;
210 fname
= g_strdup (filename
);
214 if (list_contains_name (seen_names
, fname
))
217 g_print (" cycle detected\n");
219 /* cycle detected, just return the original elf file itself */
223 debug
= get_debug_file (elf
, fname
, &debug_name
);
227 elf_parser_free (elf
);
230 seen_names
= g_list_prepend (seen_names
, fname
);
236 g_print (" no debug info file for %s\n", fname
);
243 g_list_foreach (seen_names
, (GFunc
)g_free
, NULL
);
244 g_list_free (seen_names
);
249 static GHashTable
*bin_files
;
252 bin_file_new (const char *filename
)
254 /* FIXME: should be able to return an error */
258 bin_files
= g_hash_table_new (g_str_hash
, g_str_equal
);
260 bf
= g_hash_table_lookup (bin_files
, filename
);
268 bf
= g_new0 (BinFile
, 1);
270 bf
->inode_check
= FALSE
;
271 bf
->filename
= g_strdup (filename
);
272 bf
->undefined_name
= g_strdup_printf ("In file %s", filename
);
275 g_hash_table_insert (bin_files
, bf
->filename
, bf
);
277 if (strcmp (filename
, "[vdso]") == 0)
281 const guint8
*vdso_bytes
;
283 vdso_bytes
= process_get_vdso_bytes (&length
);
286 bf
->elf
= elf_parser_new_from_data (vdso_bytes
, length
);
288 g_print ("got vdso elf: %p (%d)\n", bf
->elf
, length
);
297 bf
->elf
= elf_parser_new (filename
, NULL
);
300 g_print ("Could not parse file %s\n", filename
);
304 /* We need the text offset of the actual binary, not the
305 * (potential) debug binary
311 bf
->text_offset
= elf_parser_get_text_offset (bf
->elf
);
313 g_print ("text offset: %d\n", bf
->text_offset
);
319 g_print ("trying to find separate debug file for %s\n", filename
);
321 bf
->elf
= find_separate_debug_file (bf
->elf
, filename
);
325 g_print (" returned NULL\n");
326 else if (bf
->elf
!= oldelf
)
327 g_print (" successfully opened a different elf file than the original\n");
329 g_print (" opened the original elf file\n");
331 bf
->inode
= get_inode (filename
);
339 bin_file_free (BinFile
*bin_file
)
341 if (--bin_file
->ref_count
== 0)
343 g_hash_table_remove (bin_files
, bin_file
->filename
);
346 elf_parser_free (bin_file
->elf
);
348 g_free (bin_file
->filename
);
349 g_free (bin_file
->undefined_name
);
355 bin_file_lookup_symbol (BinFile
*bin_file
,
361 g_print ("bin file lookup lookup %d\n", address
);
363 address
-= bin_file
->text_offset
;
365 const ElfSym
*sym
= elf_parser_lookup_symbol (bin_file
->elf
, address
);
368 g_print ("lookup %d in %s\n", address
, bin_file
->filename
);
374 g_print ("found %lx => %s\n", address
, bin_symbol_get_name (bin_file
, sym
));
376 return (const BinSymbol
*)sym
;
381 g_print ("no elf file for %s\n", bin_file
->filename
);
385 g_print ("%lx undefined in %s (textoffset %d)\n", address
+ bin_file
->text_offset
, bin_file
->filename
, bin_file
->text_offset
);
388 return (const BinSymbol
*)bin_file
->undefined_name
;
392 bin_file_check_inode (BinFile
*bin_file
,
395 if (bin_file
->inode
== inode
)
401 if (!bin_file
->inode_check
)
403 g_print ("warning: Inode mismatch for %s (disk: %lld, memory: %lld)\n",
405 (guint64
)bin_file
->inode
, (guint64
)inode
);
407 bin_file
->inode_check
= TRUE
;
414 bin_symbol_get_name (BinFile
*file
,
415 const BinSymbol
*symbol
)
417 if (file
->undefined_name
== (char *)symbol
)
418 return file
->undefined_name
;
420 return elf_parser_get_sym_name (file
->elf
, (const ElfSym
*)symbol
);