summaryrefslogtreecommitdiff
path: root/src/frames.c
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2007-11-24 20:32:54 +0000
committerChris Wilson <chris@chris-wilson.co.uk>2007-11-24 20:32:54 +0000
commitccb52888d2c9a8584717767353c06f9a59a0109a (patch)
treed6d959d68f652ee84ff642a8b464f609582ecf43 /src/frames.c
parent8b043b39b92ff29aebcf596ef6508d76097046ad (diff)
Move source files into src/
Diffstat (limited to 'src/frames.c')
-rw-r--r--src/frames.c230
1 files changed, 230 insertions, 0 deletions
diff --git a/src/frames.c b/src/frames.c
new file mode 100644
index 0000000..6f311cb
--- /dev/null
+++ b/src/frames.c
@@ -0,0 +1,230 @@
+#include "memfault.h"
+
+typedef struct _frame {
+ guint ip;
+ const gchar *function;
+ const gchar *object;
+ const gchar *file;
+ const gchar *directory;
+ gint line;
+ gchar *function_srcloc;
+ gboolean is_alloc_fn;
+ guint alloc_fns_serial;
+} Frame;
+
+struct _frames {
+ GHashTable *frames;
+
+ GList *alloc_fns;
+ guint alloc_fns_serial;
+};
+
+static void
+_frame_destroy (gpointer data)
+{
+ Frame *f = data;
+
+ g_free (f->function_srcloc);
+ g_free (f);
+}
+
+const gchar *
+frames_get_function (Frames *frames, guint ip)
+{
+ Frame *f = g_hash_table_lookup (frames->frames, GUINT_TO_POINTER (ip));
+ return f ? f->function : NULL;
+}
+
+const gchar *
+frames_get_function_with_srcloc (Frames *frames, guint ip)
+{
+ Frame *f = g_hash_table_lookup (frames->frames, GUINT_TO_POINTER (ip));
+ return f ? f->function_srcloc : NULL;
+}
+
+gchar *
+frames_get_source_path (Frames *frames, guint ip)
+{
+ Frame *f;
+
+ f = g_hash_table_lookup (frames->frames, GUINT_TO_POINTER (ip));
+ if (f == NULL)
+ return NULL;
+
+ if (f->file == NULL)
+ return NULL;
+ if (f->directory == NULL)
+ return g_strdup (f->file);
+
+ return g_strconcat (f->directory, G_DIR_SEPARATOR_S, f->file, NULL);
+}
+
+void
+frames_add (Frames *frames,
+ guint ip,
+ const gchar *function,
+ const gchar *object,
+ const gchar *file,
+ const gchar *directory,
+ gint line)
+{
+ Frame *f;
+ GString *string;
+ gchar *tmp;
+
+ f = g_hash_table_lookup (frames->frames, GUINT_TO_POINTER (ip));
+ if (f != NULL)
+ return;
+
+ f = g_new (Frame, 1);
+ f->ip = ip;
+ tmp = NULL;
+ if (function == NULL && object != NULL) {
+ tmp = g_strdup_printf ("(within %s)", object);
+ }
+ f->function = function ? g_intern_string (function) :
+ object ? g_intern_string (tmp) :
+ g_intern_string ("???");
+ if (tmp != NULL)
+ g_free (tmp);
+ f->object = object ? g_intern_string (object) : NULL;
+ f->file = file ? g_intern_string (file) : NULL;
+ f->directory = directory ? g_intern_string (directory) : NULL;
+ f->line = line;
+
+ string = g_string_new ("");
+ if (function) {
+ g_string_append (string, function);
+ if (file == NULL && object != NULL) {
+ g_string_append_printf (string, " (in %s)", object);
+ }
+ } else if (file == NULL && object != NULL) {
+ g_string_append_printf (string, "(within %s)", object);
+ } else {
+ g_string_append (string, "???");
+ }
+
+ if (file != NULL)
+ g_string_append_printf (string, " (%s:%d)", file, line);
+ f->function_srcloc = g_string_free (string, FALSE);
+
+ f->alloc_fns_serial = 0;
+ f->is_alloc_fn = FALSE;
+
+ g_hash_table_insert (frames->frames, GUINT_TO_POINTER (ip), f);
+}
+
+gboolean
+frames_has_ip (Frames *frames, guint ip)
+{
+ return g_hash_table_lookup (frames->frames, GUINT_TO_POINTER (ip)) != NULL;
+}
+
+gboolean
+frames_is_alloc_fn (Frames *frames, guint ip)
+{
+ GList *l;
+ Frame *f;
+
+ f = g_hash_table_lookup (frames->frames, GUINT_TO_POINTER (ip));
+ if (f == NULL)
+ return FALSE;
+
+ if (f->function == NULL)
+ return FALSE; /* XXX or TRUE? */
+
+ if (f->alloc_fns_serial == frames->alloc_fns_serial)
+ return f->is_alloc_fn;
+
+ for (l = frames->alloc_fns; l != NULL; l = g_list_next (l))
+ if (g_regex_match (l->data, f->function, 0, NULL))
+ break;
+ f->is_alloc_fn = l != NULL;
+ f->alloc_fns_serial = frames->alloc_fns_serial;
+
+ return f->is_alloc_fn;
+}
+
+gboolean
+frames_add_alloc_fn (Frames *frames, const gchar *pattern, GError **error)
+{
+ GRegex *regex = g_regex_new (pattern, G_REGEX_OPTIMIZE, 0, error);
+ if (regex == NULL)
+ return FALSE;
+
+ frames->alloc_fns = g_list_prepend (frames->alloc_fns, regex);
+
+ if (++frames->alloc_fns_serial == 0)
+ frames->alloc_fns_serial = 1;
+
+ return TRUE;
+}
+
+guint
+frames_get_alloc_fns_serial (Frames *frames)
+{
+ return frames->alloc_fns_serial;
+}
+
+static void
+_frames_init_alloc_fns (Frames *frames)
+{
+ const gchar *patterns[] = {
+ "malloc",
+ "operator new\\(unsigned\\)",
+ "operator new\\[\\]\\(unsigned\\)",
+ "operator new\\(unsigned, std::nothrow_t const&\\)",
+ "operator new\\[\\]\\(unsigned, std::nothrow_t const&\\)",
+ "__builtin_new",
+ "__builtin_vec_new",
+ "calloc",
+ "realloc",
+ "memalign",
+
+ "g_.*alloc",
+ "(strn?|mem)dup",
+ "ft_.*alloc", /* FreeType */
+ "_hb_.*alloc" /* HarfBuzz */
+
+ };
+ guint n;
+
+ for (n = 0; n < G_N_ELEMENTS (patterns); n++) {
+ GError *error = NULL;
+ GRegex *regex = g_regex_new (patterns[n], G_REGEX_OPTIMIZE, 0, &error);
+ if (regex != NULL) {
+ frames->alloc_fns = g_list_prepend (frames->alloc_fns, regex);
+ } else {
+ g_warning ("Failed to compile builtin regex '%s': %s",
+ patterns[n], error->message);
+ g_error_free (error);
+ }
+ }
+
+ frames->alloc_fns_serial = 1;
+}
+
+Frames *
+frames_create (void)
+{
+ Frames *frames;
+
+ frames = g_new (Frames, 1);
+ frames->frames = g_hash_table_new_full (NULL, NULL, NULL, _frame_destroy);
+ frames->alloc_fns = NULL;
+ frames->alloc_fns_serial = 0;
+
+ _frames_init_alloc_fns (frames);
+
+ return frames;
+}
+
+void
+frames_destroy (Frames *frames)
+{
+ g_list_foreach (frames->alloc_fns, (GFunc) g_regex_unref, NULL);
+ g_list_free (frames->alloc_fns);
+
+ g_hash_table_destroy (frames->frames);
+ g_free (frames);
+}