----- "Lai Jiangshan" <laijs@xxxxxxxxxxxxxx> wrote: > Subject: [PATCH] crash-trace-command: generate trace.dat from > core-file > > This patch adds a command "trace dump -t" for crash-trace-command > which is extension of crash(8) for analyzing and dumping ftrace from > core-file. > > This extension already has "trace show" to show what events had happened > before crash, but it is just 1000 lines of code and it is not so > smart as "trace-cmd report". New command "trace dump -t" generates a trace.dat, > and then, we can use "trace-cmd report" for this trace.dat. > > trace-cmd(1) is a ftrace tool written by Steven Rostedt <rostedt@xxxxxxxxxxx>. > It includes two tools for showing ftrace events "trace-cmd report" and "kernelshark". > SEE ALSO: trace-cmd(1), trace-cmd-report(1), trace-cmd.dat(5) > > Note, this patch does not just improve crash-trace-command, it improves trace-cmd > also. It makes trace-cmd can handle ftrace even the kernel crashed. > > Usage: > 1) start crash(8) for a core-file, and execute the following command in crash(8): > 2) extend <your-path-to-crash-trace-command, example: /usr/lib/crash/trace.so> > 3) trace dump -t > 4) q<enter> to quit crash > 5) trace-cmd report or kernelshark > > Signed-off-by: Lai Jiangshan <laijs@xxxxxxxxxxxxxx> Queued for the next release. Thanks, Dave > --- > trace.c | 778 > +++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- > 1 file changed, 693 insertions(+), 85 deletions(-) > diff --git a/extensions/trace.c b/extensions/trace.c > index 89eb477..d100869 100755 > --- a/extensions/trace.c > +++ b/extensions/trace.c > @@ -1,7 +1,7 @@ > /* > * trace extension module for crash > * > - * Copyright (C) 2009 FUJITSU LIMITED > + * Copyright (C) 2009, 2010 FUJITSU LIMITED > * Author: Lai Jiangshan <laijs@xxxxxxxxxxxxxx> > * > * This program is free software; you can redistribute it and/or > modify > @@ -53,6 +53,7 @@ static int koffset(list_head, next); > static int koffset(ftrace_event_call, list); > static int koffset(ftrace_event_call, name); > static int koffset(ftrace_event_call, system); > +static int koffset(ftrace_event_call, print_fmt); > static int koffset(ftrace_event_call, id); > static int koffset(ftrace_event_call, fields); > > @@ -74,8 +75,11 @@ struct ring_buffer_per_cpu { > ulong reader_page; > ulong real_head_page; > > - ulong *pages; > int head_page_index; > + ulong *pages; > + > + ulong *linear_pages; > + int nr_linear_pages; > > ulong overrun; > ulong entries; > @@ -112,6 +116,22 @@ static void ftrace_show_destroy(void); > /* Remove the "const" qualifiers for ptr */ > #define free(ptr) free((void *)(ptr)) > > +static int write_and_check(int fd, void *data, size_t size) > +{ > + size_t tot = 0; > + size_t w; > + > + do { > + w = write(fd, data, size - tot); > + tot += w; > + > + if (w <= 0) > + return -1; > + } while (tot != size); > + > + return 0; > +} > + > #ifndef PATH_MAX > #define PATH_MAX 4096 > #endif > @@ -153,6 +173,7 @@ static void init_offsets(void) > init_offset(ftrace_event_call, list); > init_offset(ftrace_event_call, name); > init_offset(ftrace_event_call, system); > + init_offset(ftrace_event_call, print_fmt); > init_offset(ftrace_event_call, id); > init_offset(ftrace_event_call, fields); > > @@ -199,6 +220,7 @@ static void print_offsets(void) > print_offset(ftrace_event_call, list); > print_offset(ftrace_event_call, name); > print_offset(ftrace_event_call, system); > + print_offset(ftrace_event_call, print_fmt); > print_offset(ftrace_event_call, id); > print_offset(ftrace_event_call, fields); > > @@ -214,7 +236,7 @@ static void print_offsets(void) > static int ftrace_init_pages(struct ring_buffer_per_cpu *cpu_buffer, > unsigned nr_pages) > { > - unsigned j = 0; > + unsigned j = 0, count = 0; > ulong head, page; > ulong real_head_page = cpu_buffer->head_page; > > @@ -222,6 +244,12 @@ static int ftrace_init_pages(struct > ring_buffer_per_cpu *cpu_buffer, > if (cpu_buffer->pages == NULL) > return -1; > > + cpu_buffer->linear_pages = calloc(sizeof(ulong), nr_pages + 1); > + if (cpu_buffer->linear_pages == NULL) { > + free(cpu_buffer->pages); > + return -1; > + } > + > if (lockless_ring_buffer) { > read_value(head, cpu_buffer->kaddr, ring_buffer_per_cpu, pages); > cpu_buffer->pages[j++] = head - koffset(buffer_page, list); > @@ -253,6 +281,8 @@ static int ftrace_init_pages(struct > ring_buffer_per_cpu *cpu_buffer, > goto out_fail; > } > > + /* find head page and head_page_index */ > + > cpu_buffer->real_head_page = real_head_page; > cpu_buffer->head_page_index = -1; > > @@ -268,10 +298,38 @@ static int ftrace_init_pages(struct > ring_buffer_per_cpu *cpu_buffer, > goto out_fail; > } > > + /* Setup linear pages */ > + > + cpu_buffer->linear_pages[count++] = cpu_buffer->reader_page; > + > + if (cpu_buffer->reader_page == cpu_buffer->commit_page) > + goto done; > + > + j = cpu_buffer->head_page_index; > + for (;;) { > + cpu_buffer->linear_pages[count++] = cpu_buffer->pages[j]; > + > + if (cpu_buffer->pages[j] == cpu_buffer->commit_page) > + break; > + > + j++; > + if (j == nr_pages) > + j = 0; > + > + if (j == cpu_buffer->head_page_index) { > + /* cpu_buffer->commit_page may be corrupted */ > + break; > + } > + } > + > +done: > + cpu_buffer->nr_linear_pages = count; > + > return 0; > > out_fail: > free(cpu_buffer->pages); > + free(cpu_buffer->linear_pages); > return -1; > } > > @@ -284,6 +342,7 @@ static void ftrace_destroy_buffers(struct > ring_buffer_per_cpu *buffers) > continue; > > free(buffers[i].pages); > + free(buffers[i].linear_pages); > } > } > > @@ -470,7 +529,7 @@ static void ftrace_destroy(void) > free(global_buffers); > } > > -static int ftrace_dump_page(FILE *out, ulong page, void *page_tmp) > +static int ftrace_dump_page(int fd, ulong page, void *page_tmp) > { > ulong raw_page; > > @@ -480,7 +539,8 @@ static int ftrace_dump_page(FILE *out, ulong page, > void *page_tmp) > RETURN_ON_ERROR)) > goto out_fail; > > - fwrite(page_tmp, 1, PAGESIZE(), out); > + if (write_and_check(fd, page_tmp, PAGESIZE())) > + return -1; > > return 0; > > @@ -489,33 +549,15 @@ out_fail: > } > > static > -void ftrace_dump_buffer(FILE *out, struct ring_buffer_per_cpu > *cpu_buffer, > +void ftrace_dump_buffer(int fd, struct ring_buffer_per_cpu > *cpu_buffer, > unsigned pages, void *page_tmp) > { > - unsigned i; > - > - if (ftrace_dump_page(out, cpu_buffer->reader_page, page_tmp) < 0) > - return; > - > - if (cpu_buffer->reader_page == cpu_buffer->commit_page) > - return; > - > - i = cpu_buffer->head_page_index; > - for (;;) { > - if (ftrace_dump_page(out, cpu_buffer->pages[i], page_tmp) < 0) > - break; > - > - if (cpu_buffer->pages[i] == cpu_buffer->commit_page) > - break; > - > - i++; > - if (i == pages) > - i = 0; > + int i; > > - if (i == cpu_buffer->head_page_index) { > - /* cpu_buffer->commit_page may be corrupted */ > + for (i = 0; i < cpu_buffer->nr_linear_pages; i++) { > + if (ftrace_dump_page(fd, cpu_buffer->linear_pages[i], > + page_tmp) < 0) > break; > - } > } > } > > @@ -540,7 +582,7 @@ static int ftrace_dump_buffers(const char > *per_cpu_path) > int i; > void *page_tmp; > char path[PATH_MAX]; > - FILE *out; > + int fd; > > page_tmp = malloc(PAGESIZE()); > if (page_tmp == NULL) > @@ -558,12 +600,12 @@ static int ftrace_dump_buffers(const char > *per_cpu_path) > > snprintf(path, sizeof(path), "%s/cpu%d/trace_pipe_raw", > per_cpu_path, i); > - out = fopen(path, "wb"); > - if (out == NULL) > + fd = open(path, O_WRONLY | O_CREAT, 0644); > + if (fd < 0) > goto out_fail; > > - ftrace_dump_buffer(out, cpu_buffer, global_pages, page_tmp); > - fclose(out); > + ftrace_dump_buffer(fd, cpu_buffer, global_pages, page_tmp); > + close(fd); > } > > free(page_tmp); > @@ -727,6 +769,7 @@ static void ftrace_destroy_event_types(void) > free(event_types[i]->fields); > free(event_types[i]->system); > free(event_types[i]->name); > + free(event_types[i]->print_fmt); > free(event_types[i]); > } > > @@ -746,8 +789,8 @@ static int ftrace_init_event_types(void) > read_value(event, ftrace_events, list_head, next); > while (event != ftrace_events) { > ulong call; > - ulong name_addr, system_addr; > - char name[128], system[128]; > + ulong name_addr, system_addr, print_fmt_addr; > + char name[128], system[128], print_fmt[4096]; > int id; > > call = event - koffset(ftrace_event_call, list); > @@ -756,11 +799,14 @@ static int ftrace_init_event_types(void) > read_value(id, call, ftrace_event_call, id); > read_value(name_addr, call, ftrace_event_call, name); > read_value(system_addr, call, ftrace_event_call, system); > + read_value(print_fmt_addr, call, ftrace_event_call, print_fmt); > > if (!read_string(name_addr, name, 128)) > goto out_fail; > if (!read_string(system_addr, system, 128)) > goto out_fail; > + if (!read_string(print_fmt_addr, print_fmt, 4096)) > + goto out_fail; > > /* Enlarge event types array when need */ > if (nr_event_types >= max_types) { > @@ -782,6 +828,7 @@ static int ftrace_init_event_types(void) > > aevent_type->system = strdup(system); > aevent_type->name = strdup(name); > + aevent_type->print_fmt = strdup(print_fmt); > aevent_type->id = id; > aevent_type->nfields = 0; > aevent_type->fields = NULL; > @@ -812,6 +859,7 @@ static int ftrace_init_event_types(void) > out_fail_free_aevent_type: > free(aevent_type->system); > free(aevent_type->name); > + free(aevent_type->print_fmt); > free(aevent_type); > out_fail: > ftrace_destroy_event_types(); > @@ -868,6 +916,7 @@ static int ftrace_dump_event_type(struct > event_type *t, const char *path) > char format_path[PATH_MAX]; > FILE *out; > int i; > + int common_field_count = 5; > > snprintf(format_path, sizeof(format_path), "%s/format", path); > out = fopen(format_path, "w"); > @@ -878,15 +927,40 @@ static int ftrace_dump_event_type(struct > event_type *t, const char *path) > fprintf(out, "ID: %d\n", t->id); > fprintf(out, "format:\n"); > > - for (i = 0; i < t->nfields; i++) { > - struct ftrace_field *f = &t->fields[i]; > + for (i = t->nfields - 1; i >= 0; i--) { > + /* > + * Smartly shows the array type(except dynamic array). > + * Normal: > + * field:TYPE VAR > + * If TYPE := TYPE[LEN], it is shown: > + * field:TYPE VAR[LEN] > + */ > + struct ftrace_field *field = &t->fields[i]; > + const char *array_descriptor = strchr(field->type, '['); > + > + if (!strncmp(field->type, "__data_loc", 10)) > + array_descriptor = NULL; > + > + if (!array_descriptor) { > + fprintf(out, "\tfield:%s %s;\toffset:%u;" > + "\tsize:%u;\tsigned:%d;\n", > + field->type, field->name, field->offset, > + field->size, !!field->is_signed); > + } else { > + fprintf(out, "\tfield:%.*s %s%s;\toffset:%u;" > + "\tsize:%u;\tsigned:%d;\n", > + (int)(array_descriptor - field->type), > + field->type, field->name, > + array_descriptor, field->offset, > + field->size, !!field->is_signed); > + } > > - fprintf(out, "\tfield:%s %s;\toffset:%d;\tsize:%d;\n", > - f->type, f->name, f->offset, f->size); > + if (--common_field_count == 0) > + fprintf(out, "\n"); > } > > - /* TODO */ > - fprintf(out, "\nprint fmt: \"unknow fmt from dump\"\n"); > + fprintf(out, "\nprint fmt: %s\n", t->print_fmt); > + > fclose(out); > > return 0; > @@ -918,9 +992,7 @@ static int ftrace_dump_event_types(const char > *events_path) > > struct ring_buffer_per_cpu_stream { > struct ring_buffer_per_cpu *cpu_buffer; > - ulong *pages; > void *curr_page; > - int available_pages; > int curr_page_indx; > > uint64_t ts; > @@ -932,43 +1004,11 @@ static > int ring_buffer_per_cpu_stream_init(struct ring_buffer_per_cpu > *cpu_buffer, > unsigned pages, struct ring_buffer_per_cpu_stream *s) > { > - unsigned i, count = 0; > - > s->cpu_buffer = cpu_buffer; > s->curr_page = malloc(PAGESIZE()); > if (s->curr_page == NULL) > return -1; > > - s->pages = malloc(sizeof(ulong) * (pages + 1)); > - if (s->pages == NULL) { > - free(s->curr_page); > - return -1; > - } > - > - s->pages[count++] = cpu_buffer->reader_page; > - > - if (cpu_buffer->reader_page == cpu_buffer->commit_page) > - goto pages_done; > - > - i = cpu_buffer->head_page_index; > - for (;;) { > - s->pages[count++] = cpu_buffer->pages[i]; > - > - if (cpu_buffer->pages[i] == cpu_buffer->commit_page) > - break; > - > - i++; > - if (i == pages) > - i = 0; > - > - if (i == cpu_buffer->head_page_index) { > - /* cpu_buffer->commit_page may be corrupted */ > - break; > - } > - } > - > -pages_done: > - s->available_pages = count; > s->curr_page_indx = -1; > return 0; > } > @@ -977,7 +1017,6 @@ static > void ring_buffer_per_cpu_stream_destroy(struct > ring_buffer_per_cpu_stream *s) > { > free(s->curr_page); > - free(s->pages); > } > > struct ftrace_event { > @@ -1003,7 +1042,8 @@ int ring_buffer_per_cpu_stream_get_page(struct > ring_buffer_per_cpu_stream *s) > { > ulong raw_page; > > - read_value(raw_page, s->pages[s->curr_page_indx], buffer_page, > page); > + read_value(raw_page, > s->cpu_buffer->linear_pages[s->curr_page_indx], > + buffer_page, page); > > if (!readmem(raw_page, KVADDR, s->curr_page, PAGESIZE(), > "get page context", RETURN_ON_ERROR)) > @@ -1027,18 +1067,18 @@ int > ring_buffer_per_cpu_stream_pop_event(struct ring_buffer_per_cpu_stream > *s, > > res->data = NULL; > > - if (s->curr_page_indx >= s->available_pages) > + if (s->curr_page_indx >= s->cpu_buffer->nr_linear_pages) > return -1; > > again: > if ((s->curr_page_indx == -1) || (s->offset >= s->commit)) { > s->curr_page_indx++; > > - if (s->curr_page_indx == s->available_pages) > + if (s->curr_page_indx == s->cpu_buffer->nr_linear_pages) > return -1; > > if (ring_buffer_per_cpu_stream_get_page(s) < 0) { > - s->curr_page_indx = s->available_pages; > + s->curr_page_indx = s->cpu_buffer->nr_linear_pages; > return -1; > } > > @@ -1350,6 +1390,39 @@ static int dump_saved_cmdlines(const char > *dump_tracing_dir) > return 0; > } > > +static int dump_kallsyms(const char *dump_tracing_dir) > +{ > + char path[PATH_MAX]; > + FILE *out; > + int i; > + struct syment *sp; > + > + snprintf(path, sizeof(path), "%s/kallsyms", dump_tracing_dir); > + out = fopen(path, "w"); > + if (out == NULL) > + return -1; > + > + for (sp = st->symtable; sp < st->symend; sp++) > + fprintf(out, "%lx %c %s\n", sp->value, sp->type, sp->name); > + > + for (i = 0; i < st->mods_installed; i++) { > + struct load_module *lm = &st->load_modules[i]; > + > + for (sp = lm->mod_symtable; sp <= lm->mod_symend; sp++) { > + if (!strncmp(sp->name, "_MODULE_", strlen("_MODULE_"))) > + continue; > + > + fprintf(out, "%lx %c %s\t[%s]\n", sp->value, sp->type, > + sp->name, lm->mod_name); > + } > + } > + > + fclose(out); > + return 0; > +} > + > +static int trace_cmd_data_output(int fd); > + > static void ftrace_dump(int argc, char *argv[]) > { > int c; > @@ -1359,7 +1432,7 @@ static void ftrace_dump(int argc, char *argv[]) > char path[PATH_MAX]; > int ret; > > - while ((c = getopt(argc, argv, "sm")) != EOF) { > + while ((c = getopt(argc, argv, "smt")) != EOF) { > switch(c) > { > case 's': > @@ -1368,6 +1441,23 @@ static void ftrace_dump(int argc, char > *argv[]) > case 'm': > dump_meta_data = 1; > break; > + case 't': > + if (dump_symbols || dump_meta_data || argc - optind > 1) > + cmd_usage(pc->curcmd, SYNOPSIS); > + else { > + char *trace_dat; > + int fd; > + > + if (argc - optind == 0) > + trace_dat = "trace.dat"; > + else if (argc - optind == 1) > + trace_dat = argv[optind]; > + fd = open(trace_dat, O_WRONLY | O_CREAT > + | O_TRUNC, 0644); > + trace_cmd_data_output(fd); > + close(fd); > + } > + return; > default: > cmd_usage(pc->curcmd, SYNOPSIS); > return; > @@ -1413,10 +1503,7 @@ static void ftrace_dump(int argc, char > *argv[]) > > if (dump_symbols) { > /* Dump all symbols of the kernel */ > - fprintf(fp, "\n-s option hasn't been implemented.\n"); > - fprintf(fp, "symbols is not dumpped.\n"); > - fprintf(fp, "You can use `sym -l > %s/kallsyms`\n\n", > - dump_tracing_dir); > + dump_kallsyms(dump_tracing_dir); > } > } > > @@ -2508,6 +2595,9 @@ static char *help_ftrace[] = { > " the same as debugfs/tracing.", > " -m: also dump metadata of ftrace.", > " -s: also dump symbols of the kernel <not implemented>.", > +"trace dump -t [output-file-name]", > +" dump ring_buffers and all meta data to a file that can", > +" be parsed by trace-cmd. Default output file name is > \"trace.dat\".", > NULL > }; > > @@ -2536,3 +2626,521 @@ int _fini(void) > > return 1; > } > + > +#define TRACE_CMD_FILE_VERSION_STRING "6" > + > +static inline int host_bigendian(void) > +{ > + unsigned char str[] = { 0x1, 0x2, 0x3, 0x4 }; > + unsigned int *ptr; > + > + ptr = (unsigned int *)str; > + return *ptr == 0x01020304; > +} > + > +static char *tmp_file_buf; > +static unsigned long long tmp_file_pos; > +static unsigned long long tmp_file_size; > +static int tmp_file_error; > + > +static int init_tmp_file(void) > +{ > + tmp_file_buf = malloc(4096); > + if (tmp_file_buf == NULL) > + return -1; > + > + tmp_file_pos = 0; > + tmp_file_size = 4096; > + tmp_file_error = 0; > + > + return 0; > +} > + > +static void destory_tmp_file(void) > +{ > + free(tmp_file_buf); > +} > + > +#define tmp_fprintf(fmt...) \ > +do { \ > + char *__buf = tmp_file_buf; \ > + unsigned long long __pos; \ > + \ > + if (tmp_file_error) \ > + break; \ > + __pos = tmp_file_pos; \ > + __pos += snprintf(__buf + __pos, tmp_file_size - __pos, fmt); \ > + if (__pos > tmp_file_size) { \ > + tmp_file_size = __pos + tmp_file_size; \ > + __buf = realloc(__buf, tmp_file_size); \ > + if (!__buf) { \ > + tmp_file_error = 1; \ > + break; \ > + } \ > + tmp_file_buf = __buf; \ > + __pos = tmp_file_pos; \ > + __pos += snprintf(__buf + __pos, tmp_file_size - __pos, fmt);\ > + } \ > + tmp_file_pos = __pos; \ > +} while (0) > + > +static int tmp_file_record_size4(int fd) > +{ > + unsigned int size = tmp_file_pos; > + > + if (tmp_file_error) > + return -1; > + if (write_and_check(fd, &size, 4)) > + return -1; > + return 0; > +} > + > +static int tmp_file_record_size8(int fd) > +{ > + if (tmp_file_error) > + return -1; > + if (write_and_check(fd, &tmp_file_pos, 8)) > + return -1; > + return 0; > +} > + > +static int tmp_file_flush(int fd) > +{ > + if (tmp_file_error) > + return -1; > + if (write_and_check(fd, tmp_file_buf, tmp_file_pos)) > + return -1; > + tmp_file_pos = 0; > + return 0; > +} > + > +static int save_initial_data(int fd) > +{ > + int page_size; > + char buf[20]; > + > + if (write_and_check(fd, "\027\010\104tracing", 10)) > + return -1; > + > + if (write_and_check(fd, TRACE_CMD_FILE_VERSION_STRING, > + strlen(TRACE_CMD_FILE_VERSION_STRING) + 1)) > + return -1; > + > + /* Crash ensure core file endian and the host endian are the same > */ > + if (host_bigendian()) > + buf[0] = 1; > + else > + buf[0] = 0; > + > + if (write_and_check(fd, buf, 1)) > + return -1; > + > + /* save size of long (this may not be what the kernel is) */ > + buf[0] = sizeof(long); > + if (write_and_check(fd, buf, 1)) > + return -1; > + > + page_size = PAGESIZE(); > + if (write_and_check(fd, &page_size, 4)) > + return -1; > + > + return 0; > +} > + > +static int save_header_files(int fd) > +{ > + /* save header_page */ > + if (write_and_check(fd, "header_page", 12)) > + return -1; > + > + tmp_fprintf("\tfield: u64 > timestamp;\toffset:0;\tsize:8;\tsigned:0;\n"); > + > + tmp_fprintf("\tfield: local_t commit;\toffset:8;\tsize:%u;\t" > + "signed:1;\n", (unsigned int)sizeof(long)); > + > + tmp_fprintf("\tfield: int > overwrite;\toffset:8;\tsize:%u;\tsigned:1;\n", > + (unsigned int)sizeof(long)); > + > + tmp_fprintf("\tfield: char > data;\toffset:%u;\tsize:%u;\tsigned:1;\n", > + (unsigned int)(8 + sizeof(long)), > + (unsigned int)(PAGESIZE() - 8 - sizeof(long))); > + > + if (tmp_file_record_size8(fd)) > + return -1; > + if (tmp_file_flush(fd)) > + return -1; > + > + /* save header_event */ > + if (write_and_check(fd, "header_event", 13)) > + return -1; > + > + tmp_fprintf( > + "# compressed entry header\n" > + "\ttype_len : 5 bits\n" > + "\ttime_delta : 27 bits\n" > + "\tarray : 32 bits\n" > + "\n" > + "\tpadding : type == 29\n" > + "\ttime_extend : type == 30\n" > + "\tdata max type_len == 28\n" > + ); > + > + if (tmp_file_record_size8(fd)) > + return -1; > + if (tmp_file_flush(fd)) > + return -1; > + > + return 0; > +} > + > +static int save_event_file(int fd, struct event_type *t) > +{ > + int i; > + int common_field_count = 5; > + > + tmp_fprintf("name: %s\n", t->name); > + tmp_fprintf("ID: %d\n", t->id); > + tmp_fprintf("format:\n"); > + > + for (i = t->nfields - 1; i >= 0; i--) { > + /* > + * Smartly shows the array type(except dynamic array). > + * Normal: > + * field:TYPE VAR > + * If TYPE := TYPE[LEN], it is shown: > + * field:TYPE VAR[LEN] > + */ > + struct ftrace_field *field = &t->fields[i]; > + const char *array_descriptor = strchr(field->type, '['); > + > + if (!strncmp(field->type, "__data_loc", 10)) > + array_descriptor = NULL; > + > + if (!array_descriptor) { > + tmp_fprintf("\tfield:%s %s;\toffset:%u;" > + "\tsize:%u;\tsigned:%d;\n", > + field->type, field->name, field->offset, > + field->size, !!field->is_signed); > + } else { > + tmp_fprintf("\tfield:%.*s %s%s;\toffset:%u;" > + "\tsize:%u;\tsigned:%d;\n", > + (int)(array_descriptor - field->type), > + field->type, field->name, > + array_descriptor, field->offset, > + field->size, !!field->is_signed); > + } > + > + if (--common_field_count == 0) > + tmp_fprintf("\n"); > + } > + > + tmp_fprintf("\nprint fmt: %s\n", t->print_fmt); > + > + if (tmp_file_record_size8(fd)) > + return -1; > + return tmp_file_flush(fd); > +} > + > +static int save_system_files(int fd, int *system_ids, int system_id) > +{ > + int i, total = 0; > + > + for (i = 0; i < nr_event_types; i++) { > + if (system_ids[i] == system_id) > + total++; > + } > + > + if (write_and_check(fd, &total, 4)) > + return -1; > + > + for (i = 0; i < nr_event_types; i++) { > + if (system_ids[i] != system_id) > + continue; > + > + if (save_event_file(fd, event_types[i])) > + return -1; > + } > + > + return 0; > +} > + > +static int save_events_files(int fd) > +{ > + int system_id = 1, *system_ids; > + const char *system = "ftrace"; > + int i; > + int nr_systems; > + > + system_ids = calloc(sizeof(*system_ids), nr_event_types); > + if (system_ids == NULL) > + return -1; > + > + for (;;) { > + for (i = 0; i < nr_event_types; i++) { > + if (system_ids[i]) > + continue; > + if (!system) { > + system = event_types[i]->system; > + system_ids[i] = system_id; > + continue; > + } > + if (!strcmp(event_types[i]->system, system)) > + system_ids[i] = system_id; > + } > + if (!system) > + break; > + system_id++; > + system = NULL; > + } > + > + /* ftrace events */ > + if (save_system_files(fd, system_ids, 1)) > + goto fail; > + > + /* other systems events */ > + nr_systems = system_id - 2; > + if (write_and_check(fd, &nr_systems, 4)) > + goto fail; > + for (system_id = 2; system_id < nr_systems + 2; system_id++) { > + for (i = 0; i < nr_event_types; i++) { > + if (system_ids[i] == system_id) > + break; > + } > + if (write_and_check(fd, (void *)event_types[i]->system, > + strlen(event_types[i]->system) + 1)) > + goto fail; > + if (save_system_files(fd, system_ids, system_id)) > + goto fail; > + } > + > + free(system_ids); > + return 0; > + > +fail: > + free(system_ids); > + return -1; > +} > + > +static int save_proc_kallsyms(int fd) > +{ > + int i; > + struct syment *sp; > + > + for (sp = st->symtable; sp < st->symend; sp++) > + tmp_fprintf("%lx %c %s\n", sp->value, sp->type, sp->name); > + > + for (i = 0; i < st->mods_installed; i++) { > + struct load_module *lm = &st->load_modules[i]; > + > + for (sp = lm->mod_symtable; sp <= lm->mod_symend; sp++) { > + if (!strncmp(sp->name, "_MODULE_", strlen("_MODULE_"))) > + continue; > + > + tmp_fprintf("%lx %c %s\t[%s]\n", sp->value, sp->type, > + sp->name, lm->mod_name); > + } > + } > + > + if (tmp_file_record_size4(fd)) > + return -1; > + return tmp_file_flush(fd); > +} > + > +static int save_ftrace_printk(int fd) > +{ > + struct syment *s, *e; > + long bprintk_fmt_s, bprintk_fmt_e; > + char string[4096]; > + long *address; > + size_t i, count; > + > + s = symbol_search("__start___trace_bprintk_fmt"); > + e = symbol_search("__stop___trace_bprintk_fmt"); > + if (s == NULL || e == NULL) > + return -1; > + > + bprintk_fmt_s = s->value; > + bprintk_fmt_e = e->value; > + count = (bprintk_fmt_e - bprintk_fmt_s) / sizeof(long); > + > + if (count == 0) { > + unsigned int size = 0; > + return write_and_check(fd, &size, 4); > + } > + > + address = malloc(count * sizeof(long)); > + if (address == NULL) > + return -1; > + > + if (!readmem(bprintk_fmt_s, KVADDR, address, count * sizeof(long), > + "get printk address", RETURN_ON_ERROR)) { > + free(address); > + return -1; > + } > + > + for (i = 0; i < count; i++) { > + size_t len = read_string(address[i], string, sizeof(string)); > + if (!len) { > + free(address); > + return -1; > + } > + > + tmp_fprintf("0x%lx : \"", address[i]); > + > + for (i = 0; string[i]; i++) { > + switch (string[i]) { > + case '\n': > + tmp_fprintf("\\n"); > + break; > + case '\t': > + tmp_fprintf("\\t"); > + break; > + case '\\': > + tmp_fprintf("\\\\"); > + break; > + case '"': > + tmp_fprintf("\\\""); > + break; > + default: > + tmp_fprintf("%c", string[i]); > + } > + } > + tmp_fprintf("\"\n"); > + } > + > + free(address); > + > + if (tmp_file_record_size4(fd)) > + return -1; > + return tmp_file_flush(fd); > +} > + > +static int save_ftrace_cmdlines(int fd) > +{ > + int i; > + struct task_context *tc = FIRST_CONTEXT(); > + > + for (i = 0; i < RUNNING_TASKS(); i++) > + tmp_fprintf("%d %s\n", (int)tc[i].pid, tc[i].comm); > + > + if (tmp_file_record_size8(fd)) > + return -1; > + return tmp_file_flush(fd); > +} > + > +static int save_res_data(int fd, int nr_cpu_buffers) > +{ > + unsigned short option = 0; > + > + if (write_and_check(fd, &nr_cpu_buffers, 4)) > + return -1; > + > + if (write_and_check(fd, "options ", 10)) > + return -1; > + > + if (write_and_check(fd, &option, 2)) > + return -1; > + > + if (write_and_check(fd, "flyrecord", 10)) > + return -1; > + > + return 0; > +} > + > +static int save_record_data(int fd, int nr_cpu_buffers) > +{ > + int i, j; > + unsigned long long offset, buffer_offset; > + void *page_tmp; > + > + offset = lseek(fd, 0, SEEK_CUR); > + offset += nr_cpu_buffers * 16; > + offset = (offset + (PAGESIZE() - 1)) & ~(PAGESIZE() - 1); > + buffer_offset = offset; > + > + for (i = 0; i < nr_cpu_ids; i++) { > + struct ring_buffer_per_cpu *cpu_buffer = &global_buffers[i]; > + unsigned long long buffer_size; > + > + if (!cpu_buffer->kaddr) > + continue; > + > + buffer_size = PAGESIZE() * cpu_buffer->nr_linear_pages; > + if (write_and_check(fd, &buffer_offset, 8)) > + return -1; > + if (write_and_check(fd, &buffer_size, 8)) > + return -1; > + buffer_offset += buffer_size; > + } > + > + page_tmp = malloc(PAGESIZE()); > + if (page_tmp == NULL) > + return -1; > + > + lseek(fd, offset, SEEK_SET); > + for (i = 0; i < nr_cpu_ids; i++) { > + struct ring_buffer_per_cpu *cpu_buffer = &global_buffers[i]; > + > + if (!cpu_buffer->kaddr) > + continue; > + > + for (j = 0; j < cpu_buffer->nr_linear_pages; j++) { > + if (ftrace_dump_page(fd, cpu_buffer->linear_pages[i], > + page_tmp) < 0) { > + free(page_tmp); > + return -1; > + } > + } > + } > + > + free(page_tmp); > + > + return 0; > +} > + > +static int __trace_cmd_data_output(int fd) > +{ > + int i; > + int nr_cpu_buffers = 0; > + > + for (i = 0; i < nr_cpu_ids; i++) { > + struct ring_buffer_per_cpu *cpu_buffer = &global_buffers[i]; > + > + if (!cpu_buffer->kaddr) > + continue; > + > + nr_cpu_buffers++; > + } > + > + if (save_initial_data(fd)) > + return -1; > + if (save_header_files(fd)) > + return -1; > + if (save_events_files(fd)) /* ftrace events and other systems events > */ > + return -1; > + if (save_proc_kallsyms(fd)) > + return -1; > + if (save_ftrace_printk(fd)) > + return -1; > + if (save_ftrace_cmdlines(fd)) > + return -1; > + if (save_res_data(fd, nr_cpu_buffers)) > + return -1; > + if (save_record_data(fd, nr_cpu_buffers)) > + return -1; > + > + return 0; > +} > + > +static int trace_cmd_data_output(int fd) > +{ > + int ret; > + > + if (init_tmp_file()) > + return -1; > + > + ret = __trace_cmd_data_output(fd); > + destory_tmp_file(); > + > + return ret; > +} -- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility