📄 trace.c
字号:
/* * linux/kernel/trace.c * * (C) Copyright 1999, 2000, 2001, 2002 - Karim Yaghmour (karym@opersys.com) * * This code is distributed under the GPL license * * Tracing management * */#include <linux/config.h>#include <linux/init.h> /* For __init */#include <linux/trace.h> /* Tracing definitions */#include <linux/errno.h> /* Miscellaneous error codes */#include <linux/stddef.h> /* NULL */#include <linux/slab.h> /* kmalloc() */#include <linux/module.h> /* EXPORT_SYMBOL */#include <linux/sched.h> /* pid_t */#ifdef CONFIG_ARM#include <asm/irq.h>#include <asm/mach/irq.h>#include <asm/arch/irq.h>#else#include <linux/irq.h> /* irq_desc */#endif/* Local variables */static int tracer_registered = 0; /* Is there a tracer registered */struct tracer * tracer = NULL; /* The registered tracer *//* Registration lock */rwlock_t tracer_register_lock = RW_LOCK_UNLOCKED;/* Trace callback table entry */struct trace_callback_table_entry{ tracer_call callback; /* The callback function */ struct trace_callback_table_entry* next; /* Next entry */};/* Trace callback table */struct trace_callback_table_entry trace_callback_table[TRACE_EV_MAX];/* Custom event description */struct custom_event_desc{ /* The event itself */ trace_new_event event; /* PID of event owner, if any */ pid_t owner_pid; /* List links */ struct custom_event_desc* next; struct custom_event_desc* prev;};/* Next event ID to be used */int next_event_id;/* Circular list of custom events */struct custom_event_desc custom_events_head;struct custom_event_desc* custom_events;/* Circular list lock */rwlock_t custom_list_lock = RW_LOCK_UNLOCKED;/**************************************************** * Register the tracer to the kernel * Return values : * 0, all is OK * -EBUSY, there already is a registered tracer * -ENOMEM, couldn't allocate memory ****************************************************/int register_tracer(tracer_call pm_trace_function){ unsigned long l_flags; /* Flags for irqsave */ /* Is there a tracer already registered */ if(tracer_registered == 1) return -EBUSY; /* Allocate memory for the tracer */ if((tracer = (struct tracer *) kmalloc(sizeof(struct tracer), GFP_ATOMIC)) == NULL) /* We couldn't allocate any memory */ return -ENOMEM; /* Lock registration variables */ write_lock_irqsave(&tracer_register_lock, l_flags); /* There is a tracer registered */ tracer_registered = 1; /* Set the tracer to the one being passed by the caller */ tracer->trace = pm_trace_function; /* Unlock registration variables */ write_unlock_irqrestore(&tracer_register_lock, l_flags); /* Initialize the tracer settings */ tracer->fetch_syscall_eip_use_bounds = 0; tracer->fetch_syscall_eip_use_depth = 0; /* Tell the caller that everything went fine */ return 0;}/*************************************************** * Unregister the currently registered tracer * Return values : * 0, all is OK * -ENOMEDIUM, there isn't a registered tracer * -ENXIO, unregestering wrong tracer ***************************************************/int unregister_tracer(tracer_call pm_trace_function){ unsigned long l_flags; /* Flags for irqsave */ /* Is there a tracer already registered */ if(tracer_registered == 0) /* Nothing to unregister */ return -ENOMEDIUM; /* Lock registration variables */ write_lock_irqsave(&tracer_register_lock, l_flags); /* Is it the tracer that was registered */ if(tracer->trace == pm_trace_function) /* There isn't any tracer in here */ tracer_registered = 0; else { /* Unlock registration variables */ write_unlock_irqrestore(&tracer_register_lock, l_flags); /* We're done here */ return -ENXIO; } /* Free the memory used by the tracing structure */ kfree(tracer); tracer = NULL; /* Unlock registration variables */ write_unlock_irqrestore(&tracer_register_lock, l_flags); /* Tell the caller that everything went OK */ return 0;}/******************************************************* * Set the tracing configuration * Parameters : * pm_trace_function, the trace function. * pm_fetch_syscall_use_depth, Use depth to fetch eip * pm_fetch_syscall_use_bounds, Use bounds to fetch eip * pm_syscall_eip_depth, Detph to fetch eip * pm_syscall_lower_bound, Lower bound eip address * pm_syscall_upper_bound, Upper bound eip address * Return values : * 0, all is OK * -ENOMEDIUM, there isn't a registered tracer * -ENXIO, wrong tracer * -EINVAL, invalid configuration *******************************************************/int trace_set_config(tracer_call pm_trace_function, int pm_fetch_syscall_use_depth, int pm_fetch_syscall_use_bounds, int pm_syscall_eip_depth, void* pm_syscall_lower_bound, void* pm_syscall_upper_bound){ /* Is there a tracer already registered */ if(tracer_registered == 0) return -ENOMEDIUM; /* Is it the tracer that was registered */ if(tracer->trace != pm_trace_function) return -ENXIO; /* Is this a valid configuration */ if((pm_fetch_syscall_use_depth && pm_fetch_syscall_use_bounds) ||(pm_syscall_lower_bound > pm_syscall_upper_bound) ||(pm_syscall_eip_depth < 0)) return -EINVAL; /* Set the configuration */ tracer->fetch_syscall_eip_use_depth = pm_fetch_syscall_use_depth; tracer->fetch_syscall_eip_use_bounds = pm_fetch_syscall_use_bounds; tracer->syscall_eip_depth = pm_syscall_eip_depth; tracer->syscall_lower_eip_bound = pm_syscall_lower_bound; tracer->syscall_upper_eip_bound = pm_syscall_upper_bound; /* Tell the caller that everything was OK */ return 0;}/******************************************************* * Get the tracing configuration * Parameters : * pm_fetch_syscall_use_depth, Use depth to fetch eip * pm_fetch_syscall_use_bounds, Use bounds to fetch eip * pm_syscall_eip_depth, Detph to fetch eip * pm_syscall_lower_bound, Lower bound eip address * pm_syscall_upper_bound, Upper bound eip address * Return values : * 0, all is OK * -ENOMEDIUM, there isn't a registered tracer *******************************************************/int trace_get_config(int* pm_fetch_syscall_use_depth, int* pm_fetch_syscall_use_bounds, int* pm_syscall_eip_depth, void** pm_syscall_lower_bound, void** pm_syscall_upper_bound){ /* Is there a tracer already registered */ if(tracer_registered == 0) return -ENOMEDIUM; /* Get the configuration */ *pm_fetch_syscall_use_depth = tracer->fetch_syscall_eip_use_depth; *pm_fetch_syscall_use_bounds = tracer->fetch_syscall_eip_use_bounds; *pm_syscall_eip_depth = tracer->syscall_eip_depth; *pm_syscall_lower_bound = tracer->syscall_lower_eip_bound; *pm_syscall_upper_bound = tracer->syscall_upper_eip_bound; /* Tell the caller that everything was OK */ return 0;}/******************************************************* * Register a callback function to be called on occurence * of given event * Parameters : * pm_trace_function, the callback function. * pm_event_id, the event ID to be monitored. * Return values : * 0, all is OK * -ENOMEM, unable to allocate memory for callback *******************************************************/int trace_register_callback(tracer_call pm_trace_function, uint8_t pm_event_id){ struct trace_callback_table_entry* p_tct_entry; /* Search for an empty entry in the callback table */ for(p_tct_entry = &(trace_callback_table[pm_event_id - 1]); p_tct_entry->next != NULL; p_tct_entry = p_tct_entry->next); /* Allocate a new callback */ if((p_tct_entry->next = kmalloc(sizeof(struct trace_callback_table_entry), GFP_ATOMIC)) == NULL) return -ENOMEM; /* Setup the new callback */ p_tct_entry->next->callback = pm_trace_function; p_tct_entry->next->next = NULL; /* Tell the caller everything is ok */ return 0;}/******************************************************* * UnRegister a callback function. * Parameters : * pm_trace_function, the callback function. * pm_event_id, the event ID that had to be monitored. * Return values : * 0, all is OK * -ENOMEDIUM, no such callback resigtered *******************************************************/int trace_unregister_callback(tracer_call pm_trace_function, uint8_t pm_event_id){ struct trace_callback_table_entry* p_tct_entry; /* Pointer to trace callback table entry */ struct trace_callback_table_entry* p_temp_entry; /* Pointer to trace callback table entry */ /* Search for the callback in the callback table */ for(p_tct_entry = &(trace_callback_table[pm_event_id - 1]); ((p_tct_entry->next != NULL) && (p_tct_entry->next->callback != pm_trace_function)); p_tct_entry = p_tct_entry->next); /* Did we find anything */ if(p_tct_entry == NULL) return -ENOMEDIUM; /* Free the callback entry */ p_temp_entry = p_tct_entry->next->next; kfree(p_tct_entry->next); p_tct_entry->next = p_temp_entry; /* Tell the caller everything is ok */ return 0;}/******************************************************* * Create a new traceable event type * Parameters : * pm_event_type, string describing event type * pm_event_desc, string used for standard formatting * pm_format_type, type of formatting used to log event * data * pm_format_data, data specific to format * pm_owner_pid, PID of event's owner (0 if none) * Return values : * New Event ID if all is OK * -ENOMEM, Unable to allocate new event *******************************************************/int _trace_create_event(char* pm_event_type, char* pm_event_desc, int pm_format_type, char* pm_format_data, pid_t pm_owner_pid){ struct custom_event_desc* p_new_event; /* Newly created event */ /* Create event */ if((p_new_event = (struct custom_event_desc*) kmalloc(sizeof(struct custom_event_desc), GFP_ATOMIC)) == NULL) return -ENOMEM; /* Initialize event properties */ p_new_event->event.type[0] = '\0'; p_new_event->event.desc[0] = '\0'; p_new_event->event.form[0] = '\0'; /* Set basic event properties */ if(pm_event_type != NULL) strncpy(p_new_event->event.type, pm_event_type, CUSTOM_EVENT_TYPE_STR_LEN); if(pm_event_desc != NULL) strncpy(p_new_event->event.desc, pm_event_desc, CUSTOM_EVENT_DESC_STR_LEN); if(pm_format_data != NULL) strncpy(p_new_event->event.form, pm_format_data, CUSTOM_EVENT_FORM_STR_LEN); /* Ensure that strings are bound */ p_new_event->event.type[CUSTOM_EVENT_TYPE_STR_LEN - 1] = '\0'; p_new_event->event.desc[CUSTOM_EVENT_DESC_STR_LEN - 1] = '\0'; p_new_event->event.form[CUSTOM_EVENT_FORM_STR_LEN - 1] = '\0'; /* Set format type */ p_new_event->event.format_type = pm_format_type; /* Give the new event a unique event ID */ p_new_event->event.id = next_event_id; next_event_id++; /* Set event's owner */ p_new_event->owner_pid = pm_owner_pid; /* Insert new event in event list */ write_lock(&custom_list_lock);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -