/* Event entry printers */ enum print_line_t print_kprobe_event(struct trace_iterator *iter, int flags) { struct kprobe_trace_entry *field; struct trace_seq *s = &iter->seq; struct trace_event *event; struct trace_probe *tp; int i; field = (struct kprobe_trace_entry *)iter->ent; event = ftrace_find_event(field->ent.type); tp = container_of(event, struct trace_probe, event); if (!trace_seq_printf(s, "%s: (", tp->call.name)) goto partial; if (!seq_print_ip_sym(s, field->ip, flags | TRACE_ITER_SYM_OFFSET)) goto partial; if (!trace_seq_puts(s, ")")) goto partial; for (i = 0; i < field->nargs; i++) if (!trace_seq_printf(s, " %s=%lx", tp->args[i].name, field->args[i])) goto partial; if (!trace_seq_puts(s, "\n")) goto partial; return TRACE_TYPE_HANDLED; partial: return TRACE_TYPE_PARTIAL_LINE; }
static void print_graph_duration(struct trace_seq *s, unsigned long long duration) { unsigned long usecs = duration / 1000; unsigned long nsecs_rem = duration % 1000; /* log10(ULONG_MAX) + '\0' */ char msecs_str[21]; char nsecs_str[5]; int len; int i; sprintf(msecs_str, "%lu", usecs); /* Print msecs */ len = s->len; trace_seq_printf(s, "%lu", usecs); /* Print nsecs (we don't want to exceed 7 numbers) */ if ((s->len - len) < 7) { snprintf(nsecs_str, MIN(sizeof(nsecs_str), 8 - len), "%03lu", nsecs_rem); trace_seq_printf(s, ".%s", nsecs_str); } len = s->len - len; trace_seq_puts(s, " us "); /* Print remaining spaces to fit the row's width */ for (i = len; i < 7; i++) trace_seq_putc(s, ' '); trace_seq_puts(s, "| "); }
static int blk_log_dump_pdu(struct trace_seq *s, const struct trace_entry *ent) { const unsigned char *pdu_buf; int pdu_len; int i, end, ret; pdu_buf = pdu_start(ent); pdu_len = te_blk_io_trace(ent)->pdu_len; if (!pdu_len) return 1; for (end = pdu_len - 1; end >= 0; end--) if (pdu_buf[end]) break; end++; if (!trace_seq_putc(s, '(')) return 0; for (i = 0; i < pdu_len; i++) { ret = trace_seq_printf(s, "%s%02x", i == 0 ? "" : " ", pdu_buf[i]); if (!ret) return ret; if (i == end && end != pdu_len - 1) return trace_seq_puts(s, " ..) "); } return trace_seq_puts(s, ") "); }
void kp_event_tostring(ktap_state *ks, struct trace_seq *seq) { struct ktap_event *e = ks->current_event; struct trace_iterator *iter; struct trace_event *ev; enum print_line_t ret = TRACE_TYPE_NO_CONSUME; /* Simulate the iterator */ /* * use temp percpu buffer as trace_iterator * we cannot use same temp buffer as printf. */ iter = kp_percpu_data(KTAP_PERCPU_DATA_BUFFER2); trace_seq_init(&iter->seq); iter->ent = e->entry; ev = &(e->call->event); if (ev) ret = ev->funcs->trace(iter, 0, ev); if (ret != TRACE_TYPE_NO_CONSUME) { struct trace_seq *s = &iter->seq; int len = s->len >= PAGE_SIZE ? PAGE_SIZE - 1 : s->len; s->buffer[len] = '\0'; trace_seq_puts(seq, s->buffer); } }
/* * The ring buffer header is special. We must manually up keep it. */ int ring_buffer_print_entry_header(struct trace_seq *s) { trace_seq_puts(s, "# compressed entry header\n"); trace_seq_puts(s, "\ttype_len : 5 bits\n"); trace_seq_puts(s, "\ttime_delta : 27 bits\n"); trace_seq_puts(s, "\tarray : 32 bits\n"); trace_seq_putc(s, '\n'); trace_seq_printf(s, "\tpadding : type == %d\n", RINGBUF_TYPE_PADDING); trace_seq_printf(s, "\ttime_extend : type == %d\n", RINGBUF_TYPE_TIME_EXTEND); trace_seq_printf(s, "\tdata max type_len == %d\n", RINGBUF_TYPE_DATA_TYPE_LEN_MAX); return !trace_seq_has_overflowed(s); }
int syscall_enter_format(struct ftrace_event_call *call, struct trace_seq *s) { int i; int nr; int ret; struct syscall_metadata *entry; struct syscall_trace_enter trace; int offset = offsetof(struct syscall_trace_enter, args); nr = syscall_name_to_nr(call->data); entry = syscall_nr_to_meta(nr); if (!entry) return 0; ret = trace_seq_printf(s, "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n", SYSCALL_FIELD(int, nr)); if (!ret) return 0; for (i = 0; i < entry->nb_args; i++) { ret = trace_seq_printf(s, "\tfield:%s %s;", entry->types[i], entry->args[i]); if (!ret) return 0; ret = trace_seq_printf(s, "\toffset:%d;\tsize:%zu;\n", offset, sizeof(unsigned long)); if (!ret) return 0; offset += sizeof(unsigned long); } trace_seq_puts(s, "\nprint fmt: \""); for (i = 0; i < entry->nb_args; i++) { ret = trace_seq_printf(s, "%s: 0x%%0%zulx%s", entry->args[i], sizeof(unsigned long), i == entry->nb_args - 1 ? "" : ", "); if (!ret) return 0; } trace_seq_putc(s, '"'); for (i = 0; i < entry->nb_args; i++) { ret = trace_seq_printf(s, ", ((unsigned long)(REC->%s))", entry->args[i]); if (!ret) return 0; } return trace_seq_putc(s, '\n'); }
static int blk_log_dump_pdu(struct trace_seq *s, const struct trace_entry *ent) { const unsigned char *pdu_buf; int pdu_len; int i, end, ret; pdu_buf = pdu_start(ent); pdu_len = te_blk_io_trace(ent)->pdu_len; if (!pdu_len) return 1; /* find the last zero that needs to be printed */ for (end = pdu_len - 1; end >= 0; end--) if (pdu_buf[end]) break; end++; if (!trace_seq_putc(s, '(')) return 0; for (i = 0; i < pdu_len; i++) { ret = trace_seq_printf(s, "%s%02x", i == 0 ? "" : " ", pdu_buf[i]); if (!ret) return ret; /* * stop when the rest is just zeroes and indicate so * with a ".." appended */ if (i == end && end != pdu_len - 1) return trace_seq_puts(s, " ..) "); } return trace_seq_puts(s, ") "); }
static int sched_switch_handler(struct trace_seq *s, struct tep_record *record, struct event_format *event, void *context) { struct format_field *field; unsigned long long val; if (tep_get_field_val(s, event, "prev_pid", record, &val, 1)) return trace_seq_putc(s, '!'); field = tep_find_any_field(event, "prev_comm"); if (field) { write_and_save_comm(field, record, s, val); trace_seq_putc(s, ':'); } trace_seq_printf(s, "%lld ", val); if (tep_get_field_val(s, event, "prev_prio", record, &val, 0) == 0) trace_seq_printf(s, "[%d] ", (int) val); if (tep_get_field_val(s, event, "prev_state", record, &val, 0) == 0) write_state(s, val); trace_seq_puts(s, " ==> "); if (tep_get_field_val(s, event, "next_pid", record, &val, 1)) return trace_seq_putc(s, '!'); field = tep_find_any_field(event, "next_comm"); if (field) { write_and_save_comm(field, record, s, val); trace_seq_putc(s, ':'); } trace_seq_printf(s, "%lld", val); if (tep_get_field_val(s, event, "next_prio", record, &val, 0) == 0) trace_seq_printf(s, " [%d]", (int) val); return 0; }
static int print_graph_nested(struct trace_seq *s, struct tep_event *event, struct tep_record *record) { struct tep_handle *pevent = event->tep; unsigned long long depth; unsigned long long val; const char *func; int ret; int i; /* No overhead */ print_graph_overhead(s, -1); /* No time */ trace_seq_puts(s, " | "); if (tep_get_field_val(s, event, "depth", record, &depth, 1)) return trace_seq_putc(s, '!'); /* Function */ for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++) trace_seq_putc(s, ' '); if (tep_get_field_val(s, event, "func", record, &val, 1)) return trace_seq_putc(s, '!'); func = tep_find_function(pevent, val); if (func) ret = trace_seq_printf(s, "%s() {", func); else ret = trace_seq_printf(s, "%llx() {", val); if (ret && fgraph_depth->set) ret = trace_seq_printf(s, " (%lld)", depth); return ret; }
static int trace_stack_handler(struct trace_seq *s, struct tep_record *record, struct tep_event *event, void *context) { struct tracecmd_ftrace *finfo = context; struct tep_format_field *field; unsigned long long addr; const char *func; void *data = record->data; field = tep_find_any_field(event, "caller"); if (!field) { trace_seq_printf(s, "<CANT FIND FIELD %s>", "caller"); return 0; } trace_seq_puts(s, "<stack trace>\n"); long_size_check(finfo); for (data += field->offset; data < record->data + record->size; data += finfo->long_size) { addr = tep_read_number(event->tep, data, finfo->long_size); if ((finfo->long_size == 8 && addr == (unsigned long long)-1) || ((int)addr == -1)) break; func = tep_find_function(event->tep, addr); if (func) trace_seq_printf(s, "=> %s (%llx)\n", func, addr); else trace_seq_printf(s, "=> %llx\n", addr); } return 0; }
int ras_mc_event_handler(struct trace_seq *s, struct pevent_record *record, struct event_format *event, void *context) { int len; unsigned long long val; struct ras_events *ras = context; time_t now; struct tm *tm; struct ras_mc_event ev; int parsed_fields = 0; /* * Newer kernels (3.10-rc1 or upper) provide an uptime clock. * On previous kernels, the way to properly generate an event would * be to inject a fake one, measure its timestamp and diff it against * gettimeofday. We won't do it here. Instead, let's use uptime, * falling-back to the event report's time, if "uptime" clock is * not available (legacy kernels). */ if (ras->use_uptime) now = record->ts/user_hz + ras->uptime_diff; else now = time(NULL); tm = localtime(&now); if (tm) strftime(ev.timestamp, sizeof(ev.timestamp), "%Y-%m-%d %H:%M:%S %z", tm); trace_seq_printf(s, "%s ", ev.timestamp); if (pevent_get_field_val(s, event, "error_count", record, &val, 1) < 0) goto parse_error; parsed_fields++; ev.error_count = val; trace_seq_printf(s, "%d ", ev.error_count); if (pevent_get_field_val(s, event, "error_type", record, &val, 1) < 0) goto parse_error; parsed_fields++; switch (val) { case HW_EVENT_ERR_CORRECTED: ev.error_type = "Corrected"; break; case HW_EVENT_ERR_UNCORRECTED: ev.error_type = "Uncorrected"; break; case HW_EVENT_ERR_FATAL: ev.error_type = "Fatal"; break; default: case HW_EVENT_ERR_INFO: ev.error_type = "Info"; } trace_seq_puts(s, ev.error_type); if (ev.error_count > 1) trace_seq_puts(s, " errors:"); else trace_seq_puts(s, " error:"); ev.msg = pevent_get_field_raw(s, event, "msg", record, &len, 1); if (!ev.msg) goto parse_error; parsed_fields++; if (*ev.msg) { trace_seq_puts(s, " "); trace_seq_puts(s, ev.msg); } ev.label = pevent_get_field_raw(s, event, "label", record, &len, 1); if (!ev.label) goto parse_error; parsed_fields++; if (*ev.label) { trace_seq_puts(s, " on "); trace_seq_puts(s, ev.label); } trace_seq_puts(s, " ("); if (pevent_get_field_val(s, event, "mc_index", record, &val, 1) < 0) goto parse_error; parsed_fields++; ev.mc_index = val; trace_seq_printf(s, "mc: %d", ev.mc_index); if (pevent_get_field_val(s, event, "top_layer", record, &val, 1) < 0) goto parse_error; parsed_fields++; ev.top_layer = (signed char) val; if (pevent_get_field_val(s, event, "middle_layer", record, &val, 1) < 0) goto parse_error; parsed_fields++; ev.middle_layer = (signed char) val; if (pevent_get_field_val(s, event, "lower_layer", record, &val, 1) < 0) goto parse_error; parsed_fields++; ev.lower_layer = (signed char) val; if (ev.top_layer >= 0 || ev.middle_layer >= 0 || ev.lower_layer >= 0) { if (ev.lower_layer >= 0) trace_seq_printf(s, " location: %d:%d:%d", ev.top_layer, ev.middle_layer, ev.lower_layer); else if (ev.middle_layer >= 0) trace_seq_printf(s, " location: %d:%d", ev.top_layer, ev.middle_layer); else trace_seq_printf(s, " location: %d", ev.top_layer); } if (pevent_get_field_val(s, event, "address", record, &val, 1) < 0) goto parse_error; parsed_fields++; ev.address = val; if (ev.address) trace_seq_printf(s, " address: 0x%08llx", ev.address); if (pevent_get_field_val(s, event, "grain_bits", record, &val, 1) < 0) goto parse_error; parsed_fields++; ev.grain = val; trace_seq_printf(s, " grain: %lld", ev.grain); if (pevent_get_field_val(s, event, "syndrome", record, &val, 1) < 0) goto parse_error; parsed_fields++; ev.syndrome = val; if (val) trace_seq_printf(s, " syndrome: 0x%08llx", ev.syndrome); ev.driver_detail = pevent_get_field_raw(s, event, "driver_detail", record, &len, 1); if (!ev.driver_detail) goto parse_error; parsed_fields++; if (*ev.driver_detail) { trace_seq_puts(s, " "); trace_seq_puts(s, ev.driver_detail); } trace_seq_puts(s, ")"); /* Insert data into the SGBD */ ras_store_mc_event(ras, &ev); #ifdef HAVE_ABRT_REPORT /* Report event to ABRT */ ras_report_mc_event(ras, &ev); #endif return 0; parse_error: /* FIXME: add a logic here to also store parse errors to SDBD */ log(ALL, LOG_ERR, "MC error handler: can't parse field #%d\n", parsed_fields); return 0; }
int kp_strfmt(ktap_state *ks, struct trace_seq *seq) { int arg = 1; size_t sfl; ktap_value *arg_fmt = kp_arg(ks, 1); int argnum = kp_arg_nr(ks); const char *strfrmt, *strfrmt_end; strfrmt = svalue(arg_fmt); sfl = rawtsvalue(arg_fmt)->tsv.len; strfrmt_end = strfrmt + sfl; while (strfrmt < strfrmt_end) { if (*strfrmt != L_ESC) trace_seq_putc(seq, *strfrmt++); else if (*++strfrmt == L_ESC) trace_seq_putc(seq, *strfrmt++); else { /* format item */ char form[MAX_FORMAT]; if (++arg > argnum) { ktap_argerror(ks, arg, "no value"); return -1; } strfrmt = scanformat(ks, strfrmt, form); switch (*strfrmt++) { case 'c': trace_seq_printf(seq, form, nvalue(kp_arg(ks, arg))); break; case 'd': case 'i': { ktap_number n = nvalue(kp_arg(ks, arg)); INTFRM_T ni = (INTFRM_T)n; addlenmod(form, INTFRMLEN); trace_seq_printf(seq, form, ni); break; } case 'p': { char str[KSYM_SYMBOL_LEN]; SPRINT_SYMBOL(str, nvalue(kp_arg(ks, arg))); trace_seq_puts(seq, str); break; } case 'o': case 'u': case 'x': case 'X': { ktap_number n = nvalue(kp_arg(ks, arg)); unsigned INTFRM_T ni = (unsigned INTFRM_T)n; addlenmod(form, INTFRMLEN); trace_seq_printf(seq, form, ni); break; } case 's': { ktap_value *v = kp_arg(ks, arg); const char *s; size_t l; if (isnil(v)) { trace_seq_puts(seq, "nil"); return 0; } if (ttisevent(v)) { kp_event_tostring(ks, seq); return 0; } s = svalue(v); l = rawtsvalue(v)->tsv.len; if (!strchr(form, '.') && l >= 100) { /* * no precision and string is too long * to be formatted; * keep original string */ trace_seq_puts(seq, s); break; } else { trace_seq_printf(seq, form, s); break; } } default: /* also treat cases `pnLlh' */ kp_error(ks, "invalid option " KTAP_QL("%%%c") " to " KTAP_QL("format"), *(strfrmt - 1)); } } } return 0; }