diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2007-11-24 20:32:54 +0000 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2007-11-24 20:32:54 +0000 |
commit | ccb52888d2c9a8584717767353c06f9a59a0109a (patch) | |
tree | d6d959d68f652ee84ff642a8b464f609582ecf43 /src/frames.c | |
parent | 8b043b39b92ff29aebcf596ef6508d76097046ad (diff) |
Move source files into src/
Diffstat (limited to 'src/frames.c')
-rw-r--r-- | src/frames.c | 230 |
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); +} |