ftrace_dump() 함수 분석
ftrace_dump() 함수 구현부는 다음과 같습니다.
01 static void ftrace_dump(int argc, char *argv[])
02 {
03 int c;
04 int i;
05 uint flags = 0;
06 char *dump_tracing_dir;
07 char instance_path[PATH_MAX];
08
09 while ((c = getopt(argc, argv, "smt")) != EOF) {
10 switch(c)
11 {
12 case 's':
13 flags |= FTRACE_DUMP_SYMBOLS;
14 break;
15 case 'm':
16 flags |= FTRACE_DUMP_META_DATA;
17 break;
18 case 't':
19 if (flags & FTRACE_DUMP_SYMBOLS ||
20 flags & FTRACE_DUMP_META_DATA ||
21 argc - optind > 1)
22 cmd_usage(pc->curcmd, SYNOPSIS);
23 else {
24 char *trace_dat = "trace.dat";
25 int fd;
26
27 if (argc - optind == 0)
28 trace_dat = "trace.dat";
29 else if (argc - optind == 1)
30 trace_dat = argv[optind];
31 fd = open(trace_dat, O_WRONLY | O_CREAT
32 | O_TRUNC, 0644);
33 trace_cmd_data_output(fd);
34 close(fd);
35 }
36 return;
37 default:
38 cmd_usage(pc->curcmd, SYNOPSIS);
39 return;
40 }
41 }
42
43 if (argc - optind == 0) {
44 dump_tracing_dir = "dump_tracing_dir";
45 } else if (argc - optind == 1) {
46 dump_tracing_dir = argv[optind];
47 } else {
48 cmd_usage(pc->curcmd, SYNOPSIS);
49 return;
50 }
51
52 if (!populate_ftrace_dir_tree(&global_trace_instance, dump_tracing_dir, flags))
53 return;
54
55 if (!multiple_instances_available || instance_count == 0)
56 return;
57
58 /* Create an instances directory, and dump instance data in there */
59 snprintf(instance_path, sizeof(instance_path),
60 "%s/instances", dump_tracing_dir);
61 if (try_mkdir(instance_path, 0755) < 0)
62 return;
63
64 /* Don't care about the flags anymore */
65 flags = 0;
66
67 for (i = 0; i < instance_count; i++)
68 {
69 struct trace_instance *ti = &trace_instances[i];
70
71 snprintf(instance_path, sizeof(instance_path),
72 "%s/instances/%s", dump_tracing_dir,
73 ti->name);
74
75 if (populate_ftrace_dir_tree(ti, instance_path, flags) < 0)
76 break;
77 }
78
79 return;
80 }
'crash > trace dump' 명령어를 입력하면 아래 루틴이 실행된다.
18 case 't':
19 if (flags & FTRACE_DUMP_SYMBOLS ||
20 flags & FTRACE_DUMP_META_DATA ||
21 argc - optind > 1)
22 cmd_usage(pc->curcmd, SYNOPSIS);
23 else {
24 char *trace_dat = "trace.dat";
25 int fd;
26
27 if (argc - optind == 0)
28 trace_dat = "trace.dat";
29 else if (argc - optind == 1)
30 trace_dat = argv[optind];
31 fd = open(trace_dat, O_WRONLY | O_CREAT
32 | O_TRUNC, 0644);
33 trace_cmd_data_output(fd);
34 close(fd);
35 }
"trace.dat"에 바이너리 포멧의 ftrace를 저장한다.
trace_cmd_data_output() 함수 분석
trace_cmd_data_output() 함수의 구현부는 다음과 같다.
01 static int trace_cmd_data_output(int fd)
02 {
03 int ret;
04
05 if (init_tmp_file())
06 return -1;
07
08 ret = __trace_cmd_data_output(fd);
09 destory_tmp_file();
10
11 return ret;
12 }
파일 디스크립터를 인자로 삼아 __trace_cmd_data_output() 함수를 호출한다.
__trace_cmd_data_output() 함수 분석
__trace_cmd_data_output() 함수의 구현부는 다음과 같다.
01 static int __trace_cmd_data_output(int fd)
02 {
03 int nr_cpu_buffers;
04 unsigned long long global_res_data_offset;
05 unsigned long long *instance_offsets;
06
07 instance_offsets = calloc(sizeof(unsigned long long), instance_count);
08
09 nr_cpu_buffers = get_nr_cpu_buffers(&global_trace_instance);
10
11 if (save_initial_data(fd))
12 return -1;
13 if (save_header_files(fd))
14 return -1;
15 if (save_events_files(fd)) /* ftrace events and other systems events */
16 return -1;
17 if (save_proc_kallsyms(fd))
18 return -1;
19 if (save_ftrace_printk(fd))
20 return -1;
21 if (save_ftrace_cmdlines(fd))
22 return -1;
23
24 /* We don't have the instance buffer offsets yet, so we'll write in 0s
25 * for now, and fix it up after we have that information available */
26 global_res_data_offset = lseek(fd, 0, SEEK_CUR);
27 if (save_res_data(fd, nr_cpu_buffers, NULL))
28 return -1;
29 if (save_record_data(fd, nr_cpu_buffers, &global_trace_instance))
30 return -1;
__trace_cmd_data_output() 함수에서 여러 함수를 호출한다.
save_initial_data()
save_header_files()
save_events_files()
save_proc_kallsyms()
save_ftrace_printk()
save_ftrace_cmdlines()
save_res_data()
save_record_data()
save_initial_data() 함수 분석
save_initial_data() 함수의 전체 코드는 다음과 같다.
01 static int save_initial_data(int fd)
02 {
03 int page_size;
04 char buf[20];
05
06 if (write_and_check(fd, "\027\010\104tracing", 10))
07 return -1;
08
09 if (write_and_check(fd, TRACE_CMD_FILE_VERSION_STRING,
10 strlen(TRACE_CMD_FILE_VERSION_STRING) + 1))
11 return -1;
12
13 /* Crash ensure core file endian and the host endian are the same */
14 if (host_bigendian())
15 buf[0] = 1;
16 else
17 buf[0] = 0;
18
19 if (write_and_check(fd, buf, 1))
20 return -1;
21
22 /* save size of long (this may not be what the kernel is) */
23 buf[0] = sizeof(long);
24 if (write_and_check(fd, buf, 1))
25 return -1;
26
27 page_size = PAGESIZE();
28 if (write_and_check(fd, &page_size, 4))
29 return -1;
30
31 return 0;
32 }
저장하려는 데이터의 헤더를 생성하는 루틴으로 보인다.
상세 루틴을 나중에 분석하자.
save_header_files() 함수 분석
save_header_files() 함수의 전체 소스는 다음과 같다.
01 static int save_header_files(int fd)
02 {
03 /* save header_page */
04 if (write_and_check(fd, "header_page", 12))
05 return -1;
06
07 tmp_fprintf("\tfield: u64 timestamp;\toffset:0;\tsize:8;\tsigned:0;\n");
08
09 tmp_fprintf("\tfield: local_t commit;\toffset:8;\tsize:%u;\t"
10 "signed:1;\n", (unsigned int)sizeof(long));
11
12 tmp_fprintf("\tfield: int overwrite;\toffset:8;\tsize:%u;\tsigned:1;\n",
13 (unsigned int)sizeof(long));
14
15 tmp_fprintf("\tfield: char data;\toffset:%u;\tsize:%u;\tsigned:1;\n",
16 (unsigned int)(8 + sizeof(long)),
17 (unsigned int)(PAGESIZE() - 8 - sizeof(long)));
18
19 if (tmp_file_record_size8(fd))
20 return -1;
21 if (tmp_file_flush(fd))
22 return -1;
23
24 /* save header_event */
25 if (write_and_check(fd, "header_event", 13))
26 return -1;
27
28 tmp_fprintf(
29 "# compressed entry header\n"
30 "\ttype_len : 5 bits\n"
31 "\ttime_delta : 27 bits\n"
32 "\tarray : 32 bits\n"
33 "\n"
34 "\tpadding : type == 29\n"
35 "\ttime_extend : type == 30\n"
36 "\tdata max type_len == 28\n"
37 );
38
39 if (tmp_file_record_size8(fd))
40 return -1;
41 if (tmp_file_flush(fd))
42 return -1;
43
44 return 0;
45 }
역시 파일의 헤더를 계속 업데이트한다.
최근 덧글