static void process_function_graph_exit(struct pevent *pevent, struct pevent_record *record) { unsigned long long depth; unsigned long long val; int pid; int ret; ret = pevent_read_number_field(common_pid_field, record->data, &val); if (ret < 0) die("no pid field for function graph exit?"); ret = pevent_read_number_field(function_graph_exit_depth_field, record->data, &depth); if (ret < 0) die("no parent ip field for function?"); pid = val; if (current_pid >= 0 && pid != current_pid) { save_stack(); restore_stack(pid); } current_pid = pid; if (ips_idx != depth) { save_call_chain(pid, ips, ips_idx, 0); while (ips_idx > depth) pop_stack_func(); } func_depth = depth - 1; }
static void process_kmalloc(struct pevent *pevent, struct pevent_record *record, struct format_field *callsite_field, struct format_field *bytes_req_field, struct format_field *bytes_alloc_field, struct format_field *ptr_field) { unsigned long long callsite; unsigned long long val; unsigned long long ptr; unsigned int req; int alloc; const char *func; pevent_read_number_field(callsite_field, record->data, &callsite); pevent_read_number_field(bytes_req_field, record->data, &val); req = val; pevent_read_number_field(bytes_alloc_field, record->data, &val); alloc = val; pevent_read_number_field(ptr_field, record->data, &ptr); func = pevent_find_function(pevent, callsite); add_kmalloc(func, ptr, req, alloc); }
static void process_function(struct pevent *pevent, struct pevent_record *record) { unsigned long long parent_ip; unsigned long long ip; unsigned long long val; const char *parent; const char *func; int pid; int ret; ret = pevent_read_number_field(common_pid_field, record->data, &val); if (ret < 0) die("no pid field for function?"); ret = pevent_read_number_field(function_ip_field, record->data, &ip); if (ret < 0) die("no ip field for function?"); ret = pevent_read_number_field(function_parent_ip_field, record->data, &parent_ip); if (ret < 0) die("no parent ip field for function?"); pid = val; func = pevent_find_function(pevent, ip); parent = pevent_find_function(pevent, parent_ip); if (current_pid >= 0 && pid != current_pid) { save_stack(); restore_stack(pid); } current_pid = pid; if (ips_idx) { if (ips[ips_idx - 1] == parent) push_stack_func(func); else { save_call_chain(pid, ips, ips_idx, 0); while (ips_idx) { pop_stack_func(); if (ips[ips_idx - 1] == parent) { push_stack_func(func); break; } } } } /* The above check can set ips_idx to zero again */ if (!ips_idx) { push_stack_func(parent); push_stack_func(func); } }
static unsigned long long get_value(struct event_format *event, struct format_field *field, struct pevent_record *record) { unsigned long long val; /* Handle our dummy "comm" field */ if (field == &comm) { const char *name; name = get_comm(event, record); return (unsigned long)name; } pevent_read_number_field(field, record->data, &val); if (!(field->flags & FIELD_IS_SIGNED)) return val; switch (field->size) { case 1: return (char)val; case 2: return (short)val; case 4: return (int)val; case 8: return (long long)val; } return val; }
static void process_record(struct pevent *pevent, struct pevent_record *record) { unsigned long long val; int type; pevent_read_number_field(common_type_field, record->data, &val); type = val; if (type == function_type) return process_function(pevent, record); if (type == function_graph_entry_type) return process_function_graph_entry(pevent, record); if (type == function_graph_exit_type) return process_function_graph_exit(pevent, record); if (type == kernel_stack_type) return process_kernel_stack(pevent, record); if (type == sched_wakeup_type || type == sched_wakeup_new_type) process_sched_wakeup(pevent, record, type); else if (type == sched_switch_type) process_sched_switch(pevent, record); process_event(pevent, record, type); }
static void process_event(struct pevent *pevent, struct pevent_record *record, int type) { struct event_format *event; const char *event_name; unsigned long long val; int pid; int ret; if (pending_pid >= 0) { save_call_chain(pending_pid, pending_ips, pending_ips_idx, 1); reset_pending_stack(); } event = pevent_data_event_from_type(pevent, type); event_name = event->name; ret = pevent_read_number_field(common_pid_field, record->data, &val); if (ret < 0) die("no pid field for function?"); pid = val; /* * Even if function or function graph tracer is running, * if the user ran with stack traces on events, we want to use * that instead. But unfortunately, that stack doesn't come * until after the event. Thus, we only add the event into * the pending stack. */ push_stack_func(event_name); copy_stack_to_pending(pid); pop_stack_func(); }
static void process_function_graph_entry(struct pevent *pevent, struct pevent_record *record) { unsigned long long depth; unsigned long long ip; unsigned long long val; const char *func; int pid; int ret; ret = pevent_read_number_field(common_pid_field, record->data, &val); if (ret < 0) die("no pid field for function graph entry?"); ret = pevent_read_number_field(function_graph_entry_func_field, record->data, &ip); if (ret < 0) die("no ip field for function graph entry?"); ret = pevent_read_number_field(function_graph_entry_depth_field, record->data, &depth); if (ret < 0) die("no parent ip field for function entry?"); pid = val; func = pevent_find_function(pevent, ip); if (current_pid >= 0 && pid != current_pid) { save_stack(); restore_stack(pid); } current_pid = pid; if (depth != ips_idx) { save_call_chain(pid, ips, ips_idx, 0); while (ips_idx > depth) pop_stack_func(); } func_depth = depth; push_stack_func(func); }
gint get_wakeup_new_pid(TraceViewStore *store, struct pevent *pevent, struct record *record) { unsigned long long val; int ret; ret = pevent_read_number_field(store->sched_wakeup_new_pid_field, record->data, &val); return val; }
static void process_kfree(struct pevent *pevent, struct pevent_record *record, struct format_field *ptr_field) { unsigned long long ptr; pevent_read_number_field(ptr_field, record->data, &ptr); remove_kmalloc(ptr); }
static void process_sched_switch(struct pevent *pevent, struct pevent_record *record) { unsigned long long val; const char *comm; int pid; int ret; comm = (char *)(record->data + sched_switch_prev_field->offset); ret = pevent_read_number_field(sched_switch_prev_pid_field, record->data, &val); if (ret < 0) die("no prev_pid field in sched_switch?"); pid = val; pevent_register_comm(pevent, comm, pid); comm = (char *)(record->data + sched_switch_next_field->offset); ret = pevent_read_number_field(sched_switch_next_pid_field, record->data, &val); if (ret < 0) die("no next_pid field in sched_switch?"); pid = val; pevent_register_comm(pevent, comm, pid); }
unsigned long long raw_field_value(struct event_format *event, const char *name, void *data) { struct format_field *field; unsigned long long val; field = pevent_find_any_field(event, name); if (!field) return 0ULL; pevent_read_number_field(field, data, &val); return val; }
static void process_sched_wakeup(struct pevent *pevent, struct pevent_record *record, int type) { unsigned long long val; const char *comm; int pid; int ret; if (type == sched_wakeup_type) { comm = (char *)(record->data + sched_wakeup_comm_field->offset); ret = pevent_read_number_field(sched_wakeup_pid_field, record->data, &val); if (ret < 0) die("no pid field in sched_wakeup?"); } else { comm = (char *)(record->data + sched_wakeup_new_comm_field->offset); ret = pevent_read_number_field(sched_wakeup_new_pid_field, record->data, &val); if (ret < 0) die("no pid field in sched_wakeup_new?"); } pid = val; pevent_register_comm(pevent, comm, pid); }
static void process_record(struct pevent *pevent, struct pevent_record *record) { unsigned long long val; int type; pevent_read_number_field(common_type_field, record->data, &val); type = val; if (type == kmalloc_type) return process_kmalloc(pevent, record, kmalloc_callsite_field, kmalloc_bytes_req_field, kmalloc_bytes_alloc_field, kmalloc_ptr_field); if (type == kmalloc_node_type) return process_kmalloc(pevent, record, kmalloc_node_callsite_field, kmalloc_node_bytes_req_field, kmalloc_node_bytes_alloc_field, kmalloc_node_ptr_field); if (type == kfree_type) return process_kfree(pevent, record, kfree_ptr_field); if (type == kmem_cache_alloc_type) return process_kmalloc(pevent, record, kmem_cache_callsite_field, kmem_cache_bytes_req_field, kmem_cache_bytes_alloc_field, kmem_cache_ptr_field); if (type == kmem_cache_alloc_node_type) return process_kmalloc(pevent, record, kmem_cache_node_callsite_field, kmem_cache_node_bytes_req_field, kmem_cache_node_bytes_alloc_field, kmem_cache_node_ptr_field); if (type == kmem_cache_free_type) return process_kfree(pevent, record, kmem_cache_free_ptr_field); }
static void process_kernel_stack(struct pevent *pevent, struct pevent_record *record) { struct format_field *field = kernel_stack_caller_field; unsigned long long val; void *data = record->data; int do_restore = 0; int pid; int ret; ret = pevent_read_number_field(common_pid_field, record->data, &val); if (ret < 0) die("no pid field for function?"); pid = val; if (pending_pid >= 0 && pid != pending_pid) { reset_pending_stack(); return; } if (!field) die("no caller field for kernel stack?"); if (pending_pid >= 0) { if (current_pid >= 0) { save_stack(); do_restore = 1; } } else { /* function stack trace? */ if (current_pid >= 0) { copy_stack_to_pending(current_pid); free(ips); reset_stack(); } } current_pid = pid; /* Need to start at the end of the callers and work up */ for (data += field->offset; data < record->data + record->size; data += long_size) { unsigned long long addr; addr = pevent_read_number(pevent, data, long_size); if ((long_size == 8 && addr == (unsigned long long)-1) || ((int)addr == -1)) break; } for (data -= long_size; data >= record->data + field->offset; data -= long_size) { unsigned long long addr; const char *func; addr = pevent_read_number(pevent, data, long_size); func = pevent_find_function(pevent, addr); if (func) push_stack_func(func); } if (pending_pid >= 0) { push_stack_func(pending_ips[pending_ips_idx - 1]); reset_pending_stack(); } save_call_chain(current_pid, ips, ips_idx, 1); if (do_restore) restore_stack(current_pid); }