X-Git-Url: http://git.lttng.org/?a=blobdiff_plain;f=libmarkers%2Fmarker.c;h=43dfff7f58d38a5e06506d5a9c73d6b130e6229f;hb=20b37a3100b0d8722b361f62fd592520264fb9fa;hp=38206225ae1e309e57bd47e59c9e2065a5c31bdb;hpb=68c1021b2136a6aea5dbbe138c5103e30b5d8712;p=ust.git diff --git a/libmarkers/marker.c b/libmarkers/marker.c index 3820622..43dfff7 100644 --- a/libmarkers/marker.c +++ b/libmarkers/marker.c @@ -15,23 +15,30 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern struct marker __start___markers[]; -extern struct marker __stop___markers[]; +//ust// #include +//ust// #include +//ust// #include +#include "jhash.h" +#include "list.h" +#include "rcupdate.h" +//ust// #include +#include +//ust// #include +//ust// #include +//ust// #include +//ust// #include +//ust// #include +//ust// #include + +#include "marker.h" +#include "kernelcompat.h" +#include "usterr.h" +#include "channels.h" +#include "tracercore.h" +#include "tracer.h" + +extern struct marker __start___markers[] __attribute__((visibility("hidden"))); +extern struct marker __stop___markers[] __attribute__((visibility("hidden"))); /* Set to 1 to enable marker debug output */ static const int marker_debug; @@ -112,7 +119,7 @@ notrace void __mark_empty_function(const struct marker *mdata, void *probe_private, void *call_private, const char *fmt, va_list *args) { } -EXPORT_SYMBOL_GPL(__mark_empty_function); +//ust// EXPORT_SYMBOL_GPL(__mark_empty_function); /* * marker_probe_cb Callback that prepares the variable argument list for probes. @@ -135,7 +142,7 @@ notrace void marker_probe_cb(const struct marker *mdata, * sure the teardown of the callbacks can be done correctly when they * are in modules and they insure RCU read coherency. */ - rcu_read_lock_sched_notrace(); +//ust// rcu_read_lock_sched_notrace(); ptype = mdata->ptype; if (likely(!ptype)) { marker_probe_func *func; @@ -173,9 +180,9 @@ notrace void marker_probe_cb(const struct marker *mdata, va_end(args); } } - rcu_read_unlock_sched_notrace(); +//ust// rcu_read_unlock_sched_notrace(); } -EXPORT_SYMBOL_GPL(marker_probe_cb); +//ust// EXPORT_SYMBOL_GPL(marker_probe_cb); /* * marker_probe_cb Callback that does not prepare the variable argument list. @@ -191,7 +198,7 @@ static notrace void marker_probe_cb_noarg(const struct marker *mdata, va_list args; /* not initialized */ char ptype; - rcu_read_lock_sched_notrace(); +//ust// rcu_read_lock_sched_notrace(); ptype = mdata->ptype; if (likely(!ptype)) { marker_probe_func *func; @@ -224,7 +231,7 @@ static notrace void marker_probe_cb_noarg(const struct marker *mdata, multi[i].func(mdata, multi[i].probe_private, call_private, mdata->format, &args); } - rcu_read_unlock_sched_notrace(); +//ust// rcu_read_unlock_sched_notrace(); } static void free_old_closure(struct rcu_head *head) @@ -577,36 +584,36 @@ static int set_marker(struct marker_entry *entry, struct marker *elem, smp_wmb(); elem->ptype = entry->ptype; - if (elem->tp_name && (active ^ _imv_read(elem->state))) { - WARN_ON(!elem->tp_cb); - /* - * It is ok to directly call the probe registration because type - * checking has been done in the __trace_mark_tp() macro. - */ - - if (active) { - /* - * try_module_get should always succeed because we hold - * markers_mutex to get the tp_cb address. - */ - ret = try_module_get(__module_text_address( - (unsigned long)elem->tp_cb)); - BUG_ON(!ret); - ret = tracepoint_probe_register_noupdate( - elem->tp_name, - elem->tp_cb); - } else { - ret = tracepoint_probe_unregister_noupdate( - elem->tp_name, - elem->tp_cb); - /* - * tracepoint_probe_update_all() must be called - * before the module containing tp_cb is unloaded. - */ - module_put(__module_text_address( - (unsigned long)elem->tp_cb)); - } - } +//ust// if (elem->tp_name && (active ^ _imv_read(elem->state))) { +//ust// WARN_ON(!elem->tp_cb); +//ust// /* +//ust// * It is ok to directly call the probe registration because type +//ust// * checking has been done in the __trace_mark_tp() macro. +//ust// */ +//ust// +//ust// if (active) { +//ust// /* +//ust// * try_module_get should always succeed because we hold +//ust// * markers_mutex to get the tp_cb address. +//ust// */ +//ust// ret = try_module_get(__module_text_address( +//ust// (unsigned long)elem->tp_cb)); +//ust// BUG_ON(!ret); +//ust// ret = tracepoint_probe_register_noupdate( +//ust// elem->tp_name, +//ust// elem->tp_cb); +//ust// } else { +//ust// ret = tracepoint_probe_unregister_noupdate( +//ust// elem->tp_name, +//ust// elem->tp_cb); +//ust// /* +//ust// * tracepoint_probe_update_all() must be called +//ust// * before the module containing tp_cb is unloaded. +//ust// */ +//ust// module_put(__module_text_address( +//ust// (unsigned long)elem->tp_cb)); +//ust// } +//ust// } elem->state__imv = active; return ret; @@ -623,21 +630,21 @@ static void disable_marker(struct marker *elem) int ret; /* leave "call" as is. It is known statically. */ - if (elem->tp_name && _imv_read(elem->state)) { - WARN_ON(!elem->tp_cb); - /* - * It is ok to directly call the probe registration because type - * checking has been done in the __trace_mark_tp() macro. - */ - ret = tracepoint_probe_unregister_noupdate(elem->tp_name, - elem->tp_cb); - WARN_ON(ret); - /* - * tracepoint_probe_update_all() must be called - * before the module containing tp_cb is unloaded. - */ - module_put(__module_text_address((unsigned long)elem->tp_cb)); - } +//ust// if (elem->tp_name && _imv_read(elem->state)) { +//ust// WARN_ON(!elem->tp_cb); +//ust// /* +//ust// * It is ok to directly call the probe registration because type +//ust// * checking has been done in the __trace_mark_tp() macro. +//ust// */ +//ust// ret = tracepoint_probe_unregister_noupdate(elem->tp_name, +//ust// elem->tp_cb); +//ust// WARN_ON(ret); +//ust// /* +//ust// * tracepoint_probe_update_all() must be called +//ust// * before the module containing tp_cb is unloaded. +//ust// */ +//ust// module_put(__module_text_address((unsigned long)elem->tp_cb)); +//ust// } elem->state__imv = 0; elem->single.func = __mark_empty_function; /* Update the function before setting the ptype */ @@ -671,6 +678,20 @@ void marker_update_probe_range(struct marker *begin, /* * ignore error, continue */ + + /* This is added for UST. We emit a core_marker_id event + * for markers that are already registered to a probe + * upon library load. Otherwise, no core_marker_id will + * be generated for these markers. Is this the right thing + * to do? + */ + trace_mark(metadata, core_marker_id, + "channel %s name %s event_id %hu " + "int #1u%zu long #1u%zu pointer #1u%zu " + "size_t #1u%zu alignment #1u%u", + iter->channel, iter->name, mark_entry->event_id, + sizeof(int), sizeof(long), sizeof(void *), + sizeof(size_t), ltt_get_alignment()); } else { disable_marker(iter); } @@ -698,13 +719,14 @@ void marker_update_probe_range(struct marker *begin, static void marker_update_probes(void) { /* Core kernel markers */ - marker_update_probe_range(__start___markers, __stop___markers); +//ust// marker_update_probe_range(__start___markers, __stop___markers); /* Markers in modules. */ - module_update_markers(); - tracepoint_probe_update_all(); +//ust// module_update_markers(); + lib_update_markers(); +//ust// tracepoint_probe_update_all(); /* Update immediate values */ core_imv_update(); - module_imv_update(); +//ust// module_imv_update(); marker_update_processes(); } @@ -795,6 +817,7 @@ int marker_probe_register(const char *channel, const char *name, /* write rcu_pending before calling the RCU callback */ smp_wmb(); call_rcu_sched(&entry->rcu, free_old_closure); + /*synchronize_rcu(); free_old_closure();*/ goto end; error_unregister_channel: @@ -807,7 +830,7 @@ end: mutex_unlock(&markers_mutex); return ret; } -EXPORT_SYMBOL_GPL(marker_probe_register); +//ust// EXPORT_SYMBOL_GPL(marker_probe_register); /** * marker_probe_unregister - Disconnect a probe from a marker @@ -857,7 +880,7 @@ end: mutex_unlock(&markers_mutex); return ret; } -EXPORT_SYMBOL_GPL(marker_probe_unregister); +//ust// EXPORT_SYMBOL_GPL(marker_probe_unregister); static struct marker_entry * get_marker_from_private_data(marker_probe_func *probe, void *probe_private) @@ -945,7 +968,7 @@ end: kfree(name); return ret; } -EXPORT_SYMBOL_GPL(marker_probe_unregister_private_data); +//ust// EXPORT_SYMBOL_GPL(marker_probe_unregister_private_data); /** * marker_get_private_data - Get a marker's probe private data @@ -995,7 +1018,7 @@ void *marker_get_private_data(const char *channel, const char *name, } return ERR_PTR(-ENOENT); } -EXPORT_SYMBOL_GPL(marker_get_private_data); +//ust// EXPORT_SYMBOL_GPL(marker_get_private_data); /** * markers_compact_event_ids - Compact markers event IDs and reassign channels @@ -1003,29 +1026,29 @@ EXPORT_SYMBOL_GPL(marker_get_private_data); * Called when no channel users are active by the channel infrastructure. * Called with lock_markers() and channel mutex held. */ -void markers_compact_event_ids(void) -{ - struct marker_entry *entry; - unsigned int i; - struct hlist_head *head; - struct hlist_node *node; - int ret; - - for (i = 0; i < MARKER_TABLE_SIZE; i++) { - head = &marker_table[i]; - hlist_for_each_entry(entry, node, head, hlist) { - ret = ltt_channels_get_index_from_name(entry->channel); - WARN_ON(ret < 0); - entry->channel_id = ret; - ret = _ltt_channels_get_event_id(entry->channel, - entry->name); - WARN_ON(ret < 0); - entry->event_id = ret; - } - } -} - -#ifdef CONFIG_MODULES +//ust// void markers_compact_event_ids(void) +//ust// { +//ust// struct marker_entry *entry; +//ust// unsigned int i; +//ust// struct hlist_head *head; +//ust// struct hlist_node *node; +//ust// int ret; +//ust// +//ust// for (i = 0; i < MARKER_TABLE_SIZE; i++) { +//ust// head = &marker_table[i]; +//ust// hlist_for_each_entry(entry, node, head, hlist) { +//ust// ret = ltt_channels_get_index_from_name(entry->channel); +//ust// WARN_ON(ret < 0); +//ust// entry->channel_id = ret; +//ust// ret = _ltt_channels_get_event_id(entry->channel, +//ust// entry->name); +//ust// WARN_ON(ret < 0); +//ust// entry->event_id = ret; +//ust// } +//ust// } +//ust// } + +//ust//#ifdef CONFIG_MODULES /** * marker_get_iter_range - Get a next marker iterator given a range. @@ -1047,21 +1070,22 @@ int marker_get_iter_range(struct marker **marker, struct marker *begin, return 1; return 0; } -EXPORT_SYMBOL_GPL(marker_get_iter_range); +//ust// EXPORT_SYMBOL_GPL(marker_get_iter_range); static void marker_get_iter(struct marker_iter *iter) { int found = 0; /* Core kernel markers */ - if (!iter->module) { + if (!iter->lib) { + /* ust FIXME: how come we cannot disable the following line? we shouldn't need core stuff */ found = marker_get_iter_range(&iter->marker, __start___markers, __stop___markers); if (found) goto end; } /* Markers in modules. */ - found = module_get_iter_markers(iter); + found = lib_get_iter_markers(iter); end: if (!found) marker_iter_reset(iter); @@ -1071,7 +1095,7 @@ void marker_iter_start(struct marker_iter *iter) { marker_get_iter(iter); } -EXPORT_SYMBOL_GPL(marker_iter_start); +//ust// EXPORT_SYMBOL_GPL(marker_iter_start); void marker_iter_next(struct marker_iter *iter) { @@ -1083,19 +1107,19 @@ void marker_iter_next(struct marker_iter *iter) */ marker_get_iter(iter); } -EXPORT_SYMBOL_GPL(marker_iter_next); +//ust// EXPORT_SYMBOL_GPL(marker_iter_next); void marker_iter_stop(struct marker_iter *iter) { } -EXPORT_SYMBOL_GPL(marker_iter_stop); +//ust// EXPORT_SYMBOL_GPL(marker_iter_stop); void marker_iter_reset(struct marker_iter *iter) { - iter->module = NULL; + iter->lib = NULL; iter->marker = NULL; } -EXPORT_SYMBOL_GPL(marker_iter_reset); +//ust// EXPORT_SYMBOL_GPL(marker_iter_reset); #ifdef CONFIG_MARKERS_USERSPACE /* @@ -1114,141 +1138,141 @@ static void free_user_marker(char __user *state, struct hlist_head *head) } } -asmlinkage long sys_marker(char __user *name, char __user *format, - char __user *state, int reg) -{ - struct user_marker *umark; - long len; - struct marker_entry *entry; - int ret = 0; - - printk(KERN_DEBUG "Program %s %s marker [%p, %p]\n", - current->comm, reg ? "registers" : "unregisters", - name, state); - if (reg) { - umark = kmalloc(sizeof(struct user_marker), GFP_KERNEL); - umark->name[MAX_USER_MARKER_NAME_LEN - 1] = '\0'; - umark->format[MAX_USER_MARKER_FORMAT_LEN - 1] = '\0'; - umark->state = state; - len = strncpy_from_user(umark->name, name, - MAX_USER_MARKER_NAME_LEN - 1); - if (len < 0) { - ret = -EFAULT; - goto error; - } - len = strncpy_from_user(umark->format, format, - MAX_USER_MARKER_FORMAT_LEN - 1); - if (len < 0) { - ret = -EFAULT; - goto error; - } - printk(KERN_DEBUG "Marker name : %s, format : %s", umark->name, - umark->format); - mutex_lock(&markers_mutex); - entry = get_marker("userspace", umark->name); - if (entry) { - if (entry->format && - strcmp(entry->format, umark->format) != 0) { - printk(" error, wrong format in process %s", - current->comm); - ret = -EPERM; - goto error_unlock; - } - printk(" %s", !!entry->refcount - ? "enabled" : "disabled"); - if (put_user(!!entry->refcount, state)) { - ret = -EFAULT; - goto error_unlock; - } - printk("\n"); - } else { - printk(" disabled\n"); - if (put_user(0, umark->state)) { - printk(KERN_WARNING - "Marker in %s caused a fault\n", - current->comm); - goto error_unlock; - } - } - mutex_lock(¤t->group_leader->user_markers_mutex); - hlist_add_head(&umark->hlist, - ¤t->group_leader->user_markers); - current->group_leader->user_markers_sequence++; - mutex_unlock(¤t->group_leader->user_markers_mutex); - mutex_unlock(&markers_mutex); - } else { - mutex_lock(¤t->group_leader->user_markers_mutex); - free_user_marker(state, - ¤t->group_leader->user_markers); - current->group_leader->user_markers_sequence++; - mutex_unlock(¤t->group_leader->user_markers_mutex); - } - goto end; -error_unlock: - mutex_unlock(&markers_mutex); -error: - kfree(umark); -end: - return ret; -} - -/* - * Types : - * string : 0 - */ -asmlinkage long sys_trace(int type, uint16_t id, - char __user *ubuf) -{ - long ret = -EPERM; - char *page; - int len; - - switch (type) { - case 0: /* String */ - ret = -ENOMEM; - page = (char *)__get_free_page(GFP_TEMPORARY); - if (!page) - goto string_out; - len = strncpy_from_user(page, ubuf, PAGE_SIZE); - if (len < 0) { - ret = -EFAULT; - goto string_err; - } - trace_mark(userspace, string, "string %s", page); -string_err: - free_page((unsigned long) page); -string_out: - break; - default: - break; - } - return ret; -} - -static void marker_update_processes(void) -{ - struct task_struct *g, *t; - - /* - * markers_mutex is taken to protect the p->user_markers read. - */ - mutex_lock(&markers_mutex); - read_lock(&tasklist_lock); - for_each_process(g) { - WARN_ON(!thread_group_leader(g)); - if (hlist_empty(&g->user_markers)) - continue; - if (strcmp(g->comm, "testprog") == 0) - printk(KERN_DEBUG "set update pending for testprog\n"); - t = g; - do { - /* TODO : implement this thread flag in each arch. */ - set_tsk_thread_flag(t, TIF_MARKER_PENDING); - } while ((t = next_thread(t)) != g); - } - read_unlock(&tasklist_lock); - mutex_unlock(&markers_mutex); -} +//ust// asmlinkage long sys_marker(char __user *name, char __user *format, +//ust// char __user *state, int reg) +//ust// { +//ust// struct user_marker *umark; +//ust// long len; +//ust// struct marker_entry *entry; +//ust// int ret = 0; +//ust// +//ust// printk(KERN_DEBUG "Program %s %s marker [%p, %p]\n", +//ust// current->comm, reg ? "registers" : "unregisters", +//ust// name, state); +//ust// if (reg) { +//ust// umark = kmalloc(sizeof(struct user_marker), GFP_KERNEL); +//ust// umark->name[MAX_USER_MARKER_NAME_LEN - 1] = '\0'; +//ust// umark->format[MAX_USER_MARKER_FORMAT_LEN - 1] = '\0'; +//ust// umark->state = state; +//ust// len = strncpy_from_user(umark->name, name, +//ust// MAX_USER_MARKER_NAME_LEN - 1); +//ust// if (len < 0) { +//ust// ret = -EFAULT; +//ust// goto error; +//ust// } +//ust// len = strncpy_from_user(umark->format, format, +//ust// MAX_USER_MARKER_FORMAT_LEN - 1); +//ust// if (len < 0) { +//ust// ret = -EFAULT; +//ust// goto error; +//ust// } +//ust// printk(KERN_DEBUG "Marker name : %s, format : %s", umark->name, +//ust// umark->format); +//ust// mutex_lock(&markers_mutex); +//ust// entry = get_marker("userspace", umark->name); +//ust// if (entry) { +//ust// if (entry->format && +//ust// strcmp(entry->format, umark->format) != 0) { +//ust// printk(" error, wrong format in process %s", +//ust// current->comm); +//ust// ret = -EPERM; +//ust// goto error_unlock; +//ust// } +//ust// printk(" %s", !!entry->refcount +//ust// ? "enabled" : "disabled"); +//ust// if (put_user(!!entry->refcount, state)) { +//ust// ret = -EFAULT; +//ust// goto error_unlock; +//ust// } +//ust// printk("\n"); +//ust// } else { +//ust// printk(" disabled\n"); +//ust// if (put_user(0, umark->state)) { +//ust// printk(KERN_WARNING +//ust// "Marker in %s caused a fault\n", +//ust// current->comm); +//ust// goto error_unlock; +//ust// } +//ust// } +//ust// mutex_lock(¤t->group_leader->user_markers_mutex); +//ust// hlist_add_head(&umark->hlist, +//ust// ¤t->group_leader->user_markers); +//ust// current->group_leader->user_markers_sequence++; +//ust// mutex_unlock(¤t->group_leader->user_markers_mutex); +//ust// mutex_unlock(&markers_mutex); +//ust// } else { +//ust// mutex_lock(¤t->group_leader->user_markers_mutex); +//ust// free_user_marker(state, +//ust// ¤t->group_leader->user_markers); +//ust// current->group_leader->user_markers_sequence++; +//ust// mutex_unlock(¤t->group_leader->user_markers_mutex); +//ust// } +//ust// goto end; +//ust// error_unlock: +//ust// mutex_unlock(&markers_mutex); +//ust// error: +//ust// kfree(umark); +//ust// end: +//ust// return ret; +//ust// } +//ust// +//ust// /* +//ust// * Types : +//ust// * string : 0 +//ust// */ +//ust// asmlinkage long sys_trace(int type, uint16_t id, +//ust// char __user *ubuf) +//ust// { +//ust// long ret = -EPERM; +//ust// char *page; +//ust// int len; +//ust// +//ust// switch (type) { +//ust// case 0: /* String */ +//ust// ret = -ENOMEM; +//ust// page = (char *)__get_free_page(GFP_TEMPORARY); +//ust// if (!page) +//ust// goto string_out; +//ust// len = strncpy_from_user(page, ubuf, PAGE_SIZE); +//ust// if (len < 0) { +//ust// ret = -EFAULT; +//ust// goto string_err; +//ust// } +//ust// trace_mark(userspace, string, "string %s", page); +//ust// string_err: +//ust// free_page((unsigned long) page); +//ust// string_out: +//ust// break; +//ust// default: +//ust// break; +//ust// } +//ust// return ret; +//ust// } + +//ust// static void marker_update_processes(void) +//ust// { +//ust// struct task_struct *g, *t; +//ust// +//ust// /* +//ust// * markers_mutex is taken to protect the p->user_markers read. +//ust// */ +//ust// mutex_lock(&markers_mutex); +//ust// read_lock(&tasklist_lock); +//ust// for_each_process(g) { +//ust// WARN_ON(!thread_group_leader(g)); +//ust// if (hlist_empty(&g->user_markers)) +//ust// continue; +//ust// if (strcmp(g->comm, "testprog") == 0) +//ust// printk(KERN_DEBUG "set update pending for testprog\n"); +//ust// t = g; +//ust// do { +//ust// /* TODO : implement this thread flag in each arch. */ +//ust// set_tsk_thread_flag(t, TIF_MARKER_PENDING); +//ust// } while ((t = next_thread(t)) != g); +//ust// } +//ust// read_unlock(&tasklist_lock); +//ust// mutex_unlock(&markers_mutex); +//ust// } /* * Update current process. @@ -1332,7 +1356,7 @@ int is_marker_enabled(const char *channel, const char *name) return entry && !!entry->refcount; } -#endif +//ust// #endif int marker_module_notify(struct notifier_block *self, unsigned long val, void *data) @@ -1357,11 +1381,12 @@ struct notifier_block marker_module_nb = { .priority = 0, }; -static int init_markers(void) -{ - return register_module_notifier(&marker_module_nb); -} -__initcall(init_markers); +//ust// static int init_markers(void) +//ust// { +//ust// return register_module_notifier(&marker_module_nb); +//ust// } +//ust// __initcall(init_markers); +/* TODO: call marker_module_nb() when a library is linked at runtime (dlopen)? */ #endif /* CONFIG_MODULES */ @@ -1403,4 +1428,94 @@ void ltt_dump_marker_state(struct ltt_trace_struct *trace) } marker_iter_stop(&iter); } -EXPORT_SYMBOL_GPL(ltt_dump_marker_state); +//ust// EXPORT_SYMBOL_GPL(ltt_dump_marker_state); + + +static LIST_HEAD(libs); + +/* + * Returns 0 if current not found. + * Returns 1 if current found. + */ +int lib_get_iter_markers(struct marker_iter *iter) +{ + struct lib *iter_lib; + int found = 0; + +//ust// mutex_lock(&module_mutex); + list_for_each_entry(iter_lib, &libs, list) { + if (iter_lib < iter->lib) + continue; + else if (iter_lib > iter->lib) + iter->marker = NULL; + found = marker_get_iter_range(&iter->marker, + iter_lib->markers_start, + iter_lib->markers_start + iter_lib->markers_count); + if (found) { + iter->lib = iter_lib; + break; + } + } +//ust// mutex_unlock(&module_mutex); + return found; +} + +void lib_update_markers(void) +{ + struct lib *lib; + +//ust// mutex_lock(&module_mutex); + list_for_each_entry(lib, &libs, list) + marker_update_probe_range(lib->markers_start, + lib->markers_start + lib->markers_count); +//ust// mutex_unlock(&module_mutex); +} + +static void (*new_marker_cb)(struct marker *) = NULL; + +void marker_set_new_marker_cb(void (*cb)(struct marker *)) +{ + new_marker_cb = cb; +} + +static void new_markers(struct marker *start, struct marker *end) +{ + if(new_marker_cb) { + struct marker *m; + for(m=start; m < end; m++) { + new_marker_cb(m); + } + } +} + +int marker_register_lib(struct marker *markers_start, int markers_count) +{ + struct lib *pl; + + pl = (struct lib *) malloc(sizeof(struct lib)); + + pl->markers_start = markers_start; + pl->markers_count = markers_count; + + list_add(&pl->list, &libs); + + new_markers(markers_start, markers_start + markers_count); + + /* FIXME: update just the loaded lib */ + lib_update_markers(); + + printf("just registered a markers section from %p and having %d markers\n", markers_start, markers_count); + + return 0; +} + +static int initialized = 0; + +void __attribute__((constructor)) init_markers(void) +{ + if(!initialized) { + marker_register_lib(__start___markers, (((long)__stop___markers)-((long)__start___markers))/sizeof(struct marker)); + printf("markers_start: %p, markers_stop: %p\n", __start___markers, __stop___markers); + initialized = 1; + } +}