Simplify vdso reading in binfile.c

This commit is contained in:
Søren Sandmann Pedersen
2009-09-08 00:00:06 -04:00
parent 3d9cbe20e7
commit 604d07600a
2 changed files with 39 additions and 114 deletions

6
TODO
View File

@ -23,6 +23,10 @@ Before 1.0.4:
Before 1.2: Before 1.2:
* Make tracker creation faster
* Share map reading code between vdso stuff in binfile.c and tracker.c
* Get rid of remaining gulongs (use uint64_t instead) * Get rid of remaining gulongs (use uint64_t instead)
* Move binfile hash table to state_t. * Move binfile hash table to state_t.
@ -580,6 +584,8 @@ http://www.linuxbase.org/spec/booksets/LSB-Embedded/LSB-Embedded/ehframe.html
Later: Later:
- Multithreading is possible in a number of places.
- If the stack trace ends in a memory access instruction, send the - If the stack trace ends in a memory access instruction, send the
vma information to userspace. Then have user space vma information to userspace. Then have user space
produce statistics on what types of memory are accessed. produce statistics on what types of memory are accessed.

147
binfile.c
View File

@ -33,6 +33,7 @@
#include <stdio.h> #include <stdio.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <stdint.h>
#include "binfile.h" #include "binfile.h"
#include "elfparser.h" #include "elfparser.h"
@ -260,130 +261,49 @@ get_debug_binaries (GList *files,
static GHashTable *bin_files; static GHashTable *bin_files;
typedef struct Map Map; static char **
struct Map get_lines (const char *format, pid_t pid)
{ {
char * filename; char *filename = g_strdup_printf (format, pid);
gulong start; char **result = NULL;
gulong end; char *contents;
gulong offset;
gulong inode;
BinFile * bin_file; if (g_file_get_contents (filename, &contents, NULL, NULL))
};
static Map *
read_maps (int pid, int *n_maps)
{
char *name = g_strdup_printf ("/proc/%d/maps", pid);
char buffer[1024];
FILE *in;
GArray *result;
in = fopen (name, "r");
if (!in)
{ {
g_free (name); result = g_strsplit (contents, "\n", -1);
return NULL;
}
result = g_array_new (FALSE, FALSE, sizeof (Map));
while (fgets (buffer, sizeof (buffer) - 1, in))
{
char file[256];
int count;
gulong start;
gulong end;
gulong offset;
gulong inode;
count = sscanf ( g_free (contents);
buffer, "%lx-%lx %*15s %lx %*x:%*x %lu %255s",
&start, &end, &offset, &inode, file);
if (count == 5)
{
Map map;
map.filename = g_strdup (file);
map.start = start;
map.end = end;
if (strcmp (map.filename, "[vdso]") == 0)
{
/* For the vdso, the kernel reports 'offset' as the
* the same as the mapping addres. This doesn't make
* any sense to me, so we just zero it here. There
* is code in binfile.c (read_inode) that returns 0
* for [vdso].
*/
map.offset = 0;
map.inode = 0;
}
else
{
map.offset = offset;
map.inode = inode;
}
map.bin_file = NULL;
g_array_append_val (result, map);
}
} }
g_free (name); g_free (filename);
fclose (in);
return result;
if (n_maps)
*n_maps = result->len;
return (Map *)g_array_free (result, FALSE);
} }
static void static const uint8_t *
free_maps (int *n_maps, get_vdso_bytes (size_t *length)
Map *maps)
{
int i;
for (i = 0; i < *n_maps; ++i)
{
Map *map = &(maps[i]);
if (map->filename)
g_free (map->filename);
if (map->bin_file)
bin_file_free (map->bin_file);
}
g_free (maps);
*n_maps = 0;
}
const guint8 *
get_vdso_bytes (gsize *length)
{ {
static const uint8_t *bytes = NULL;
static size_t n_bytes = 0;
static gboolean has_data; static gboolean has_data;
static const guint8 *bytes = NULL;
static gsize n_bytes = 0;
if (!has_data) if (!has_data)
{ {
Map *maps; char **lines = get_lines ("/proc/%d/maps", getpid());
int n_maps, i; int i;
maps = read_maps (getpid(), &n_maps); for (i = 0; lines[i] != NULL; ++i)
for (i = 0; i < n_maps; ++i)
{ {
Map *map = &(maps[i]); char file[256];
gulong start;
if (strcmp (map->filename, "[vdso]") == 0) gulong end;
int count = sscanf (
lines[i], "%lx-%lx %*15s %*x %*x:%*x %*u %255s",
&start, &end, file);
if (count == 3 && strcmp (file, "[vdso]") == 0)
{ {
n_bytes = map->end - map->start; n_bytes = end - start;
/* Dup the memory here so that valgrind will only /* Dup the memory here so that valgrind will only
* report one 1 byte invalid read instead of * report one 1 byte invalid read instead of
@ -395,17 +315,16 @@ get_vdso_bytes (gsize *length)
* wrapper never returned that address. But since it * wrapper never returned that address. But since it
* is a legal mapping, it is legal to read it. * is a legal mapping, it is legal to read it.
*/ */
bytes = g_memdup ((guint8 *)map->start, n_bytes); bytes = g_memdup ((uint8_t *)start, n_bytes);
has_data = TRUE;
} }
} }
has_data = TRUE;
free_maps (&n_maps, maps);
} }
if (length) if (length)
*length = n_bytes; *length = n_bytes;
return bytes; return bytes;
} }