diff --git a/lib/meson.build b/lib/meson.build index d02d9f3a..5f9f2a5f 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -28,12 +28,14 @@ libsysprof_base_headers = [ 'sp-address.h', 'sp-clock.h', 'sp-error.h', + 'sp-kallsyms.h', ] libsysprof_base_sources = [ 'sp-address.c', 'sp-clock.c', 'sp-error.c', + 'sp-kallsyms.c', ] libsysprof_headers = libsysprof_base_headers diff --git a/lib/sp-kallsyms.c b/lib/sp-kallsyms.c new file mode 100644 index 00000000..3e799cbc --- /dev/null +++ b/lib/sp-kallsyms.c @@ -0,0 +1,148 @@ +/* sp-kallsyms.c + * + * Copyright © 2018 Christian Hergert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#define G_LOG_DOMAIN "sp-kallsyms" + +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif + +#include +#include +#include + +#include "sp-kallsyms.h" + +struct _SpKallsyms +{ + gchar *buf; + gsize buflen; + gchar *endptr; + gchar *iter; +}; + +void +sp_kallsyms_free (SpKallsyms *self) +{ + if (self != NULL) + { + g_clear_pointer (&self->buf, g_free); + g_slice_free (SpKallsyms, self); + } +} + +SpKallsyms * +sp_kallsyms_new (void) +{ + g_autoptr(SpKallsyms) self = NULL; + + self = g_slice_new0 (SpKallsyms); + + if (!g_file_get_contents ("/proc/kallsyms", &self->buf, &self->buflen, NULL)) + return NULL; + + self->iter = self->buf; + self->endptr = self->buf + self->buflen; + + return g_steal_pointer (&self); +} + +gboolean +sp_kallsyms_next (SpKallsyms *self, + const gchar **name, + guint64 *address, + guint8 *type) +{ + guint64 addr; + char *tok; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (self->buf != NULL, FALSE); + g_return_val_if_fail (self->buflen > 0, FALSE); + g_return_val_if_fail (self->iter != NULL, FALSE); + g_return_val_if_fail (self->endptr != NULL, FALSE); + +try_next: + + if (self->iter >= self->endptr) + return FALSE; + + tok = strtok_r (self->iter, " \t\n", &self->iter); + if (!tok || *tok == 0) + return FALSE; + + if (*tok == '[') + { + tok = strtok_r (self->iter, " \t\n", &self->iter); + if (!tok || *tok == 0) + return FALSE; + } + + addr = g_ascii_strtoull (tok, NULL, 10); + if ((addr == G_MAXUINT64 && errno == ERANGE) || + (addr == 0 && errno == EINVAL)) + return FALSE; + + *address = addr; + + if (self->iter >= self->endptr) + return FALSE; + + tok = strtok_r (self->iter, " \t\n", &self->iter); + if (!tok || *tok == 0) + return FALSE; + + switch (*tok) + { + case 'A': + case 'B': + case 'D': + case 'R': + case 'T': + case 'V': + case 'W': + case 'a': + case 'b': + case 'd': + case 'r': + case 't': + case 'w': + *type = *tok; + break; + + default: + return FALSE; + } + + if (self->iter >= self->endptr) + return FALSE; + + tok = strtok_r (self->iter, " \t\n", &self->iter); + if (!tok || *tok == 0) + return FALSE; + + if (self->iter >= self->endptr) + return FALSE; + + if (g_strcmp0 (tok, "(null)") == 0) + goto try_next; + + *name = tok; + + return TRUE; +} diff --git a/lib/sp-kallsyms.h b/lib/sp-kallsyms.h new file mode 100644 index 00000000..76b7a627 --- /dev/null +++ b/lib/sp-kallsyms.h @@ -0,0 +1,41 @@ +/* sp-kallsyms.h + * + * Copyright © 2018 Christian Hergert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef SP_KALLSYMS_H +#define SP_KALLSYMS_H + +#include + +#include "sp-kallsyms.h" + +G_BEGIN_DECLS + +typedef struct _SpKallsyms SpKallsyms; + +SpKallsyms *sp_kallsyms_new (void); +gboolean sp_kallsyms_next (SpKallsyms *self, + const gchar **name, + guint64 *address, + guint8 *type); +void sp_kallsyms_free (SpKallsyms *self); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (SpKallsyms, sp_kallsyms_free) + +G_END_DECLS + +#endif /* SP_KALLSYMS_H */