Add symbol resolution to tracker

This commit is contained in:
Søren Sandmann Pedersen
2009-09-07 20:43:22 -04:00
parent cdc7ce7e12
commit d34a1cf460
3 changed files with 504 additions and 362 deletions

289
process.c
View File

@ -485,295 +485,6 @@ find_kernel_binary (void)
return binary;
}
typedef struct
{
gulong address;
char *name;
} KernelSymbol;
static void
parse_kallsym_line (const char *line,
GArray *table)
{
char **tokens = g_strsplit_set (line, " \t", -1);
if (tokens[0] && tokens[1] && tokens[2])
{
glong address;
char *endptr;
address = strtoul (tokens[0], &endptr, 16);
if (*endptr == '\0' &&
(strcmp (tokens[1], "T") == 0 ||
strcmp (tokens[1], "t") == 0))
{
KernelSymbol sym;
sym.address = address;
sym.name = g_strdup (tokens[2]);
g_array_append_val (table, sym);
}
}
g_strfreev (tokens);
}
static gboolean
parse_kallsyms (const char *kallsyms,
GArray *table)
{
const char *sol;
const char *eol;
sol = kallsyms;
eol = strchr (sol, '\n');
while (eol)
{
char *line = g_strndup (sol, eol - sol);
parse_kallsym_line (line, table);
g_free (line);
sol = eol + 1;
eol = strchr (sol, '\n');
}
if (table->len <= 1)
return FALSE;
return TRUE;
}
static int
compare_syms (gconstpointer a, gconstpointer b)
{
const KernelSymbol *sym_a = a;
const KernelSymbol *sym_b = b;
if (sym_a->address > sym_b->address)
return 1;
else if (sym_a->address == sym_b->address)
return 0;
else
return -1;
}
static GArray *
get_kernel_symbols (void)
{
static GArray *kernel_syms;
static gboolean initialized = FALSE;
find_kernel_binary();
if (!initialized)
{
char *kallsyms;
if (g_file_get_contents ("/proc/kallsyms", &kallsyms, NULL, NULL))
{
if (kallsyms)
{
kernel_syms = g_array_new (TRUE, TRUE, sizeof (KernelSymbol));
if (parse_kallsyms (kallsyms, kernel_syms))
{
g_array_sort (kernel_syms, compare_syms);
}
else
{
g_array_free (kernel_syms, TRUE);
kernel_syms = NULL;
}
}
g_free (kallsyms);
}
if (!kernel_syms)
g_print ("Warning: /proc/kallsyms could not be "
"read. Kernel symbols will not be available\n");
initialized = TRUE;
}
return kernel_syms;
}
gboolean
process_is_kernel_address (gulong address)
{
GArray *ksyms = get_kernel_symbols ();
if (ksyms &&
address >= g_array_index (ksyms, KernelSymbol, 0).address &&
address < g_array_index (ksyms, KernelSymbol, ksyms->len - 1).address)
{
return TRUE;
}
return FALSE;
}
static KernelSymbol *
do_lookup (KernelSymbol *symbols,
gulong address,
int first,
int last)
{
if (address >= symbols[last].address)
{
return &(symbols[last]);
}
else if (last - first < 3)
{
while (last >= first)
{
if (address >= symbols[last].address)
return &(symbols[last]);
last--;
}
return NULL;
}
else
{
int mid = (first + last) / 2;
if (symbols[mid].address > address)
return do_lookup (symbols, address, first, mid);
else
return do_lookup (symbols, address, mid, last);
}
}
const char *
process_lookup_kernel_symbol (gulong address,
gulong *offset)
{
GArray *ksyms = get_kernel_symbols ();
KernelSymbol *result;
if (offset)
{
/* If we don't have any offset, just return 1, so it doesn't
* look like a callback
*/
*offset = 1;
}
if (ksyms->len == 0)
return NULL;
result = do_lookup ((KernelSymbol *)ksyms->data, address, 0, ksyms->len - 1);
if (result && offset)
*offset = address - result->address;
return result? result->name : NULL;
}
const char *
process_lookup_symbol (Process *process, gulong address, gulong *offset)
{
static const char *const kernel = "[kernel]";
const BinSymbol *result;
Map *map = process_locate_map (process, address);
/* g_print ("addr: %x\n", address); */
if (offset)
{
/* If we don't have any offset, just return 1, so it doesn't
* look like a callback
*/
*offset = 1;
}
if (address == 0x1)
{
return kernel;
}
else if (!map)
{
if (!process->undefined)
{
process->undefined =
g_strdup_printf ("No map (%s)", process->cmdline);
}
return process->undefined;
}
#if 0
if (strcmp (map->filename, "/home/ssp/sysprof/sysprof") == 0)
{
g_print ("YES\n");
g_print ("map address: %lx\n", map->start);
g_print ("map offset: %lx\n", map->offset);
g_print ("address before: %lx (%s)\n", address, map->filename);
}
g_print ("address before: \n");
#endif
#if 0
g_print ("%s is mapped at %lx + %lx\n", map->filename, map->start, map->offset);
g_print ("incoming address: %lx\n", address);
#endif
address -= map->start;
address += map->offset;
#if 0
if (strcmp (map->filename, "[vdso]") == 0)
{
g_print ("address after: %lx\n", address);
}
#endif
if (!map->bin_file)
map->bin_file = bin_file_new (map->filename);
/* g_print ("%s: start: %p, load: %p\n", */
/* map->filename, map->start, bin_file_get_load_address (map->bin_file)); */
if (!bin_file_check_inode (map->bin_file, map->inode))
{
/* If the inodes don't match, it's probably because the
* file has changed since the process was started. Just return
* the undefined symbol in that case.
*/
address = 0x0;
}
result = bin_file_lookup_symbol (map->bin_file, address);
#if 0
g_print (" ---> %s\n", result->name);
#endif
/* g_print ("(%x) %x %x name; %s\n", address, map->start,
* map->offset, result->name);
*/
#if 0
g_print ("name: %s (in %s)\n", bin_symbol_get_name (map->bin_file, result), map->filename);
g_print (" in addr: %lx\n", address);
g_print (" out addr: %lx\n", bin_symbol_get_address (map->bin_file, result));
g_print (" map start: %lx\n", map->start);
g_print (" map offset: %lx\n", map->offset);
#endif
if (offset)
*offset = address - bin_symbol_get_address (map->bin_file, result);
return bin_symbol_get_name (map->bin_file, result);
}
const char *
process_get_cmdline (Process *process)
{