kallsyms: make SpKallsyms more testable

This allows us to pass in the file to read from, and adds a quick test
case to view the parsed output. It also fixes a base-10 vs base-16
mistake in parsing addresses.
This commit is contained in:
Christian Hergert
2018-01-29 01:25:14 -08:00
parent af4eac025a
commit 911d51d447
6 changed files with 55 additions and 10 deletions

View File

@ -76,7 +76,7 @@ sysprofd_get_kernel_symbols (sd_bus_message *msg,
else if (r == 0) else if (r == 0)
return -EACCES; return -EACCES;
if (!(kallsyms = sp_kallsyms_new ())) if (!(kallsyms = sp_kallsyms_new (NULL)))
{ {
sd_bus_error_set (error, sd_bus_error_set (error,
SD_BUS_ERROR_FILE_NOT_FOUND, SD_BUS_ERROR_FILE_NOT_FOUND,

View File

@ -47,13 +47,16 @@ sp_kallsyms_free (SpKallsyms *self)
} }
SpKallsyms * SpKallsyms *
sp_kallsyms_new (void) sp_kallsyms_new (const gchar *path)
{ {
g_autoptr(SpKallsyms) self = NULL; g_autoptr(SpKallsyms) self = NULL;
if (path == NULL)
path = "/proc/kallsyms";
self = g_slice_new0 (SpKallsyms); self = g_slice_new0 (SpKallsyms);
if (!g_file_get_contents ("/proc/kallsyms", &self->buf, &self->buflen, NULL)) if (!g_file_get_contents (path, &self->buf, &self->buflen, NULL))
return NULL; return NULL;
self->iter = self->buf; self->iter = self->buf;
@ -70,6 +73,7 @@ sp_kallsyms_next (SpKallsyms *self,
{ {
guint64 addr; guint64 addr;
char *tok; char *tok;
char *pptr;
g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (self->buf != NULL, FALSE); g_return_val_if_fail (self->buf != NULL, FALSE);
@ -93,10 +97,12 @@ try_next:
return FALSE; return FALSE;
} }
addr = g_ascii_strtoull (tok, NULL, 10); /* We'll keep going if we fail to parse, (null) usually, so that we
if ((addr == G_MAXUINT64 && errno == ERANGE) || * just skip to the next line.
(addr == 0 && errno == EINVAL)) */
return FALSE; addr = g_ascii_strtoull (tok, &pptr, 16);
if ((pptr == tok) || (addr == G_MAXUINT64 && errno == ERANGE) || (addr == 0 && errno == EINVAL))
addr = 0;
*address = addr; *address = addr;
@ -139,7 +145,7 @@ try_next:
if (self->iter >= self->endptr) if (self->iter >= self->endptr)
return FALSE; return FALSE;
if (g_strcmp0 (tok, "(null)") == 0) if (addr == 0)
goto try_next; goto try_next;
*name = tok; *name = tok;

View File

@ -27,7 +27,7 @@ G_BEGIN_DECLS
typedef struct _SpKallsyms SpKallsyms; typedef struct _SpKallsyms SpKallsyms;
SpKallsyms *sp_kallsyms_new (void); SpKallsyms *sp_kallsyms_new (const gchar *path);
gboolean sp_kallsyms_next (SpKallsyms *self, gboolean sp_kallsyms_next (SpKallsyms *self,
const gchar **name, const gchar **name,
guint64 *address, guint64 *address,

View File

@ -189,7 +189,7 @@ sp_kernel_symbol_load (void)
kernel_symbol_strs = g_string_chunk_new (4096); kernel_symbol_strs = g_string_chunk_new (4096);
ar = g_array_new (FALSE, TRUE, sizeof (SpKernelSymbol)); ar = g_array_new (FALSE, TRUE, sizeof (SpKernelSymbol));
if (!(kallsyms = sp_kallsyms_new ())) if (!(kallsyms = sp_kallsyms_new (NULL)))
goto query_daemon; goto query_daemon;
while (sp_kallsyms_next (kallsyms, &name, &addr, &type)) while (sp_kallsyms_next (kallsyms, &name, &addr, &type))

View File

@ -18,6 +18,11 @@ test_capture_cursor = executable('test-capture-cursor',
) )
test('test-capture-cursor', test_capture_cursor, env: test_env) test('test-capture-cursor', test_capture_cursor, env: test_env)
test_kallsyms = executable('test-kallsyms',
['test-kallsyms.c', '../lib/sp-kallsyms.c'],
dependencies: libsysprof_dep,
)
if get_option('enable_gtk') if get_option('enable_gtk')
test_model_filter = executable('test-model-filter', test_model_filter = executable('test-model-filter',

34
tests/test-kallsyms.c Normal file
View File

@ -0,0 +1,34 @@
#include "../lib/sp-address.h"
#include "../lib/sp-kallsyms.h"
#include <glib.h>
#include <stdlib.h>
int
main (gint argc,
gchar *argv[])
{
g_autoptr(SpKallsyms) kallsyms = NULL;
const gchar *name;
SpAddress addr = 0;
guint8 type;
if (argc < 2)
{
g_printerr ("usage: %s FILE\n", argv[0]);
return EXIT_FAILURE;
}
kallsyms = sp_kallsyms_new (argv[1]);
while (sp_kallsyms_next (kallsyms, &name, &addr, &type))
{
g_assert (name != NULL);
g_assert (addr != 0);
g_assert (type != 0);
g_print ("%s %lx\n", name, addr);
}
return EXIT_SUCCESS;
}