1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
26c887b2aSSimon Glass /*
36c887b2aSSimon Glass * Copyright (c) 2013 Google, Inc
46c887b2aSSimon Glass */
56c887b2aSSimon Glass
66c887b2aSSimon Glass /* Decode and dump U-Boot profiling information */
76c887b2aSSimon Glass
86c887b2aSSimon Glass #include <assert.h>
96c887b2aSSimon Glass #include <ctype.h>
106c887b2aSSimon Glass #include <limits.h>
116c887b2aSSimon Glass #include <regex.h>
126c887b2aSSimon Glass #include <stdarg.h>
136c887b2aSSimon Glass #include <stdio.h>
146c887b2aSSimon Glass #include <stdlib.h>
156c887b2aSSimon Glass #include <string.h>
166c887b2aSSimon Glass #include <unistd.h>
176c887b2aSSimon Glass #include <sys/param.h>
1826e355d1SJörg Krause #include <sys/types.h>
196c887b2aSSimon Glass
206c887b2aSSimon Glass #include <compiler.h>
216c887b2aSSimon Glass #include <trace.h>
226c887b2aSSimon Glass
236c887b2aSSimon Glass #define MAX_LINE_LEN 500
246c887b2aSSimon Glass
256c887b2aSSimon Glass enum {
266c887b2aSSimon Glass FUNCF_TRACE = 1 << 0, /* Include this function in trace */
276c887b2aSSimon Glass };
286c887b2aSSimon Glass
296c887b2aSSimon Glass struct func_info {
306c887b2aSSimon Glass unsigned long offset;
316c887b2aSSimon Glass const char *name;
326c887b2aSSimon Glass unsigned long code_size;
336c887b2aSSimon Glass unsigned long call_count;
346c887b2aSSimon Glass unsigned flags;
356c887b2aSSimon Glass /* the section this function is in */
366c887b2aSSimon Glass struct objsection_info *objsection;
376c887b2aSSimon Glass };
386c887b2aSSimon Glass
396c887b2aSSimon Glass enum trace_line_type {
406c887b2aSSimon Glass TRACE_LINE_INCLUDE,
416c887b2aSSimon Glass TRACE_LINE_EXCLUDE,
426c887b2aSSimon Glass };
436c887b2aSSimon Glass
446c887b2aSSimon Glass struct trace_configline_info {
456c887b2aSSimon Glass struct trace_configline_info *next;
466c887b2aSSimon Glass enum trace_line_type type;
476c887b2aSSimon Glass const char *name; /* identifier name / wildcard */
486c887b2aSSimon Glass regex_t regex; /* Regex to use if name starts with / */
496c887b2aSSimon Glass };
506c887b2aSSimon Glass
516c887b2aSSimon Glass /* The contents of the trace config file */
526c887b2aSSimon Glass struct trace_configline_info *trace_config_head;
536c887b2aSSimon Glass
546c887b2aSSimon Glass struct func_info *func_list;
556c887b2aSSimon Glass int func_count;
566c887b2aSSimon Glass struct trace_call *call_list;
576c887b2aSSimon Glass int call_count;
586c887b2aSSimon Glass int verbose; /* Verbosity level 0=none, 1=warn, 2=notice, 3=info, 4=debug */
596c887b2aSSimon Glass unsigned long text_offset; /* text address of first function */
606c887b2aSSimon Glass
616c887b2aSSimon Glass static void outf(int level, const char *fmt, ...)
626c887b2aSSimon Glass __attribute__ ((format (__printf__, 2, 3)));
636c887b2aSSimon Glass #define error(fmt, b...) outf(0, fmt, ##b)
646c887b2aSSimon Glass #define warn(fmt, b...) outf(1, fmt, ##b)
656c887b2aSSimon Glass #define notice(fmt, b...) outf(2, fmt, ##b)
666c887b2aSSimon Glass #define info(fmt, b...) outf(3, fmt, ##b)
676c887b2aSSimon Glass #define debug(fmt, b...) outf(4, fmt, ##b)
686c887b2aSSimon Glass
696c887b2aSSimon Glass
outf(int level,const char * fmt,...)706c887b2aSSimon Glass static void outf(int level, const char *fmt, ...)
716c887b2aSSimon Glass {
726c887b2aSSimon Glass if (verbose >= level) {
736c887b2aSSimon Glass va_list args;
746c887b2aSSimon Glass
756c887b2aSSimon Glass va_start(args, fmt);
766c887b2aSSimon Glass vfprintf(stderr, fmt, args);
776c887b2aSSimon Glass va_end(args);
786c887b2aSSimon Glass }
796c887b2aSSimon Glass }
806c887b2aSSimon Glass
usage(void)816c887b2aSSimon Glass static void usage(void)
826c887b2aSSimon Glass {
836c887b2aSSimon Glass fprintf(stderr,
846c887b2aSSimon Glass "Usage: proftool -cds -v3 <cmd> <profdata>\n"
856c887b2aSSimon Glass "\n"
866c887b2aSSimon Glass "Commands\n"
876c887b2aSSimon Glass " dump-ftrace\t\tDump out textual data in ftrace format\n"
886c887b2aSSimon Glass "\n"
896c887b2aSSimon Glass "Options:\n"
906c887b2aSSimon Glass " -m <map>\tSpecify Systen.map file\n"
916c887b2aSSimon Glass " -t <trace>\tSpecific trace data file (from U-Boot)\n"
926c887b2aSSimon Glass " -v <0-4>\tSpecify verbosity\n");
936c887b2aSSimon Glass exit(EXIT_FAILURE);
946c887b2aSSimon Glass }
956c887b2aSSimon Glass
h_cmp_offset(const void * v1,const void * v2)966c887b2aSSimon Glass static int h_cmp_offset(const void *v1, const void *v2)
976c887b2aSSimon Glass {
986c887b2aSSimon Glass const struct func_info *f1 = v1, *f2 = v2;
996c887b2aSSimon Glass
1006c887b2aSSimon Glass return (f1->offset / FUNC_SITE_SIZE) - (f2->offset / FUNC_SITE_SIZE);
1016c887b2aSSimon Glass }
1026c887b2aSSimon Glass
read_system_map(FILE * fin)1036c887b2aSSimon Glass static int read_system_map(FILE *fin)
1046c887b2aSSimon Glass {
1056c887b2aSSimon Glass unsigned long offset, start = 0;
1066c887b2aSSimon Glass struct func_info *func;
1076c887b2aSSimon Glass char buff[MAX_LINE_LEN];
1086c887b2aSSimon Glass char symtype;
1096c887b2aSSimon Glass char symname[MAX_LINE_LEN + 1];
1106c887b2aSSimon Glass int linenum;
1116c887b2aSSimon Glass int alloced;
1126c887b2aSSimon Glass
1136c887b2aSSimon Glass for (linenum = 1, alloced = func_count = 0;; linenum++) {
1146c887b2aSSimon Glass int fields = 0;
1156c887b2aSSimon Glass
1166c887b2aSSimon Glass if (fgets(buff, sizeof(buff), fin))
1176c887b2aSSimon Glass fields = sscanf(buff, "%lx %c %100s\n", &offset,
1186c887b2aSSimon Glass &symtype, symname);
1196c887b2aSSimon Glass if (fields == 2) {
1206c887b2aSSimon Glass continue;
1216c887b2aSSimon Glass } else if (feof(fin)) {
1226c887b2aSSimon Glass break;
1236c887b2aSSimon Glass } else if (fields < 2) {
1246c887b2aSSimon Glass error("Map file line %d: invalid format\n", linenum);
1256c887b2aSSimon Glass return 1;
1266c887b2aSSimon Glass }
1276c887b2aSSimon Glass
1286c887b2aSSimon Glass /* Must be a text symbol */
1296c887b2aSSimon Glass symtype = tolower(symtype);
1306c887b2aSSimon Glass if (symtype != 't' && symtype != 'w')
1316c887b2aSSimon Glass continue;
1326c887b2aSSimon Glass
1336c887b2aSSimon Glass if (func_count == alloced) {
1346c887b2aSSimon Glass alloced += 256;
1356c887b2aSSimon Glass func_list = realloc(func_list,
1366c887b2aSSimon Glass sizeof(struct func_info) * alloced);
1376c887b2aSSimon Glass assert(func_list);
1386c887b2aSSimon Glass }
1396c887b2aSSimon Glass if (!func_count)
1406c887b2aSSimon Glass start = offset;
1416c887b2aSSimon Glass
1426c887b2aSSimon Glass func = &func_list[func_count++];
1436c887b2aSSimon Glass memset(func, '\0', sizeof(*func));
1446c887b2aSSimon Glass func->offset = offset - start;
1456c887b2aSSimon Glass func->name = strdup(symname);
1466c887b2aSSimon Glass func->flags = FUNCF_TRACE; /* trace by default */
1476c887b2aSSimon Glass
1486c887b2aSSimon Glass /* Update previous function's code size */
1496c887b2aSSimon Glass if (func_count > 1)
1506c887b2aSSimon Glass func[-1].code_size = func->offset - func[-1].offset;
1516c887b2aSSimon Glass }
1526c887b2aSSimon Glass notice("%d functions found in map file\n", func_count);
1536c887b2aSSimon Glass text_offset = start;
1546c887b2aSSimon Glass return 0;
1556c887b2aSSimon Glass }
1566c887b2aSSimon Glass
read_data(FILE * fin,void * buff,int size)1576c887b2aSSimon Glass static int read_data(FILE *fin, void *buff, int size)
1586c887b2aSSimon Glass {
1596c887b2aSSimon Glass int err;
1606c887b2aSSimon Glass
1616c887b2aSSimon Glass err = fread(buff, 1, size, fin);
1626c887b2aSSimon Glass if (!err)
1636c887b2aSSimon Glass return 1;
1646c887b2aSSimon Glass if (err != size) {
1656c887b2aSSimon Glass error("Cannot read profile file at pos %ld\n", ftell(fin));
1666c887b2aSSimon Glass return -1;
1676c887b2aSSimon Glass }
1686c887b2aSSimon Glass return 0;
1696c887b2aSSimon Glass }
1706c887b2aSSimon Glass
find_func_by_offset(uint32_t offset)1716c887b2aSSimon Glass static struct func_info *find_func_by_offset(uint32_t offset)
1726c887b2aSSimon Glass {
1736c887b2aSSimon Glass struct func_info key, *found;
1746c887b2aSSimon Glass
1756c887b2aSSimon Glass key.offset = offset;
1766c887b2aSSimon Glass found = bsearch(&key, func_list, func_count, sizeof(struct func_info),
1776c887b2aSSimon Glass h_cmp_offset);
1786c887b2aSSimon Glass
1796c887b2aSSimon Glass return found;
1806c887b2aSSimon Glass }
1816c887b2aSSimon Glass
1826c887b2aSSimon Glass /* This finds the function which contains the given offset */
find_caller_by_offset(uint32_t offset)1836c887b2aSSimon Glass static struct func_info *find_caller_by_offset(uint32_t offset)
1846c887b2aSSimon Glass {
1856c887b2aSSimon Glass int low; /* least function that could be a match */
1866c887b2aSSimon Glass int high; /* greated function that could be a match */
1876c887b2aSSimon Glass struct func_info key;
1886c887b2aSSimon Glass
1896c887b2aSSimon Glass low = 0;
1906c887b2aSSimon Glass high = func_count - 1;
1916c887b2aSSimon Glass key.offset = offset;
1926c887b2aSSimon Glass while (high > low + 1) {
1936c887b2aSSimon Glass int mid = (low + high) / 2;
1946c887b2aSSimon Glass int result;
1956c887b2aSSimon Glass
1966c887b2aSSimon Glass result = h_cmp_offset(&key, &func_list[mid]);
1976c887b2aSSimon Glass if (result > 0)
1986c887b2aSSimon Glass low = mid;
1996c887b2aSSimon Glass else if (result < 0)
2006c887b2aSSimon Glass high = mid;
2016c887b2aSSimon Glass else
2026c887b2aSSimon Glass return &func_list[mid];
2036c887b2aSSimon Glass }
2046c887b2aSSimon Glass
2056c887b2aSSimon Glass return low >= 0 ? &func_list[low] : NULL;
2066c887b2aSSimon Glass }
2076c887b2aSSimon Glass
read_calls(FILE * fin,int count)2086c887b2aSSimon Glass static int read_calls(FILE *fin, int count)
2096c887b2aSSimon Glass {
2106c887b2aSSimon Glass struct trace_call *call_data;
2116c887b2aSSimon Glass int i;
2126c887b2aSSimon Glass
2136c887b2aSSimon Glass notice("call count: %d\n", count);
2146c887b2aSSimon Glass call_list = (struct trace_call *)calloc(count, sizeof(*call_data));
2156c887b2aSSimon Glass if (!call_list) {
2166c887b2aSSimon Glass error("Cannot allocate call_list\n");
2176c887b2aSSimon Glass return -1;
2186c887b2aSSimon Glass }
2196c887b2aSSimon Glass call_count = count;
2206c887b2aSSimon Glass
2216c887b2aSSimon Glass call_data = call_list;
2226c887b2aSSimon Glass for (i = 0; i < count; i++, call_data++) {
2236c887b2aSSimon Glass if (read_data(fin, call_data, sizeof(*call_data)))
2246c887b2aSSimon Glass return 1;
2256c887b2aSSimon Glass }
2266c887b2aSSimon Glass return 0;
2276c887b2aSSimon Glass }
2286c887b2aSSimon Glass
read_profile(FILE * fin,int * not_found)2296c887b2aSSimon Glass static int read_profile(FILE *fin, int *not_found)
2306c887b2aSSimon Glass {
2316c887b2aSSimon Glass struct trace_output_hdr hdr;
2326c887b2aSSimon Glass
2336c887b2aSSimon Glass *not_found = 0;
2346c887b2aSSimon Glass while (!feof(fin)) {
2356c887b2aSSimon Glass int err;
2366c887b2aSSimon Glass
2376c887b2aSSimon Glass err = read_data(fin, &hdr, sizeof(hdr));
2386c887b2aSSimon Glass if (err == 1)
2396c887b2aSSimon Glass break; /* EOF */
2406c887b2aSSimon Glass else if (err)
2416c887b2aSSimon Glass return 1;
2426c887b2aSSimon Glass
2436c887b2aSSimon Glass switch (hdr.type) {
2446c887b2aSSimon Glass case TRACE_CHUNK_FUNCS:
2456c887b2aSSimon Glass /* Ignored at present */
2466c887b2aSSimon Glass break;
2476c887b2aSSimon Glass
2486c887b2aSSimon Glass case TRACE_CHUNK_CALLS:
2496c887b2aSSimon Glass if (read_calls(fin, hdr.rec_count))
2506c887b2aSSimon Glass return 1;
2516c887b2aSSimon Glass break;
2526c887b2aSSimon Glass }
2536c887b2aSSimon Glass }
2546c887b2aSSimon Glass return 0;
2556c887b2aSSimon Glass }
2566c887b2aSSimon Glass
read_map_file(const char * fname)2576c887b2aSSimon Glass static int read_map_file(const char *fname)
2586c887b2aSSimon Glass {
2596c887b2aSSimon Glass FILE *fmap;
2606c887b2aSSimon Glass int err = 0;
2616c887b2aSSimon Glass
2626c887b2aSSimon Glass fmap = fopen(fname, "r");
2636c887b2aSSimon Glass if (!fmap) {
2646c887b2aSSimon Glass error("Cannot open map file '%s'\n", fname);
2656c887b2aSSimon Glass return 1;
2666c887b2aSSimon Glass }
2676c887b2aSSimon Glass if (fmap) {
2686c887b2aSSimon Glass err = read_system_map(fmap);
2696c887b2aSSimon Glass fclose(fmap);
2706c887b2aSSimon Glass }
2716c887b2aSSimon Glass return err;
2726c887b2aSSimon Glass }
2736c887b2aSSimon Glass
read_profile_file(const char * fname)2746c887b2aSSimon Glass static int read_profile_file(const char *fname)
2756c887b2aSSimon Glass {
2766c887b2aSSimon Glass int not_found = INT_MAX;
2776c887b2aSSimon Glass FILE *fprof;
2786c887b2aSSimon Glass int err;
2796c887b2aSSimon Glass
2806c887b2aSSimon Glass fprof = fopen(fname, "rb");
2816c887b2aSSimon Glass if (!fprof) {
2826c887b2aSSimon Glass error("Cannot open profile data file '%s'\n",
2836c887b2aSSimon Glass fname);
2846c887b2aSSimon Glass return 1;
2856c887b2aSSimon Glass } else {
2866c887b2aSSimon Glass err = read_profile(fprof, ¬_found);
2876c887b2aSSimon Glass fclose(fprof);
2886c887b2aSSimon Glass if (err)
2896c887b2aSSimon Glass return err;
2906c887b2aSSimon Glass
2916c887b2aSSimon Glass if (not_found) {
2926c887b2aSSimon Glass warn("%d profile functions could not be found in the map file - are you sure that your profile data and map file correspond?\n",
2936c887b2aSSimon Glass not_found);
2946c887b2aSSimon Glass return 1;
2956c887b2aSSimon Glass }
2966c887b2aSSimon Glass }
2976c887b2aSSimon Glass return 0;
2986c887b2aSSimon Glass }
2996c887b2aSSimon Glass
regex_report_error(regex_t * regex,int err,const char * op,const char * name)3006c887b2aSSimon Glass static int regex_report_error(regex_t *regex, int err, const char *op,
3016c887b2aSSimon Glass const char *name)
3026c887b2aSSimon Glass {
3036c887b2aSSimon Glass char buf[200];
3046c887b2aSSimon Glass
3056c887b2aSSimon Glass regerror(err, regex, buf, sizeof(buf));
3066c887b2aSSimon Glass error("Regex error '%s' in %s '%s'\n", buf, op, name);
3076c887b2aSSimon Glass return -1;
3086c887b2aSSimon Glass }
3096c887b2aSSimon Glass
check_trace_config_line(struct trace_configline_info * item)3106c887b2aSSimon Glass static void check_trace_config_line(struct trace_configline_info *item)
3116c887b2aSSimon Glass {
3126c887b2aSSimon Glass struct func_info *func, *end;
3136c887b2aSSimon Glass int err;
3146c887b2aSSimon Glass
3156c887b2aSSimon Glass debug("Checking trace config line '%s'\n", item->name);
3166c887b2aSSimon Glass for (func = func_list, end = func + func_count; func < end; func++) {
3176c887b2aSSimon Glass err = regexec(&item->regex, func->name, 0, NULL, 0);
3186c887b2aSSimon Glass debug(" - regex '%s', string '%s': %d\n", item->name,
3196c887b2aSSimon Glass func->name, err);
3206c887b2aSSimon Glass if (err == REG_NOMATCH)
3216c887b2aSSimon Glass continue;
3226c887b2aSSimon Glass
323d4125ebcSAndreas Bießmann if (err) {
3246c887b2aSSimon Glass regex_report_error(&item->regex, err, "match",
3256c887b2aSSimon Glass item->name);
3266c887b2aSSimon Glass break;
3276c887b2aSSimon Glass }
3286c887b2aSSimon Glass
3296c887b2aSSimon Glass /* It matches, so perform the action */
3306c887b2aSSimon Glass switch (item->type) {
3316c887b2aSSimon Glass case TRACE_LINE_INCLUDE:
3326c887b2aSSimon Glass info(" include %s at %lx\n", func->name,
3336c887b2aSSimon Glass text_offset + func->offset);
3346c887b2aSSimon Glass func->flags |= FUNCF_TRACE;
3356c887b2aSSimon Glass break;
3366c887b2aSSimon Glass
3376c887b2aSSimon Glass case TRACE_LINE_EXCLUDE:
3386c887b2aSSimon Glass info(" exclude %s at %lx\n", func->name,
3396c887b2aSSimon Glass text_offset + func->offset);
3406c887b2aSSimon Glass func->flags &= ~FUNCF_TRACE;
3416c887b2aSSimon Glass break;
3426c887b2aSSimon Glass }
3436c887b2aSSimon Glass }
3446c887b2aSSimon Glass }
3456c887b2aSSimon Glass
check_trace_config(void)3466c887b2aSSimon Glass static void check_trace_config(void)
3476c887b2aSSimon Glass {
3486c887b2aSSimon Glass struct trace_configline_info *line;
3496c887b2aSSimon Glass
3506c887b2aSSimon Glass for (line = trace_config_head; line; line = line->next)
3516c887b2aSSimon Glass check_trace_config_line(line);
3526c887b2aSSimon Glass }
3536c887b2aSSimon Glass
3546c887b2aSSimon Glass /**
3556c887b2aSSimon Glass * Check the functions to see if they each have an objsection. If not, then
3566c887b2aSSimon Glass * the linker must have eliminated them.
3576c887b2aSSimon Glass */
check_functions(void)3586c887b2aSSimon Glass static void check_functions(void)
3596c887b2aSSimon Glass {
3606c887b2aSSimon Glass struct func_info *func, *end;
3616c887b2aSSimon Glass unsigned long removed_code_size = 0;
3626c887b2aSSimon Glass int not_found = 0;
3636c887b2aSSimon Glass
3646c887b2aSSimon Glass /* Look for missing functions */
3656c887b2aSSimon Glass for (func = func_list, end = func + func_count; func < end; func++) {
3666c887b2aSSimon Glass if (!func->objsection) {
3676c887b2aSSimon Glass removed_code_size += func->code_size;
3686c887b2aSSimon Glass not_found++;
3696c887b2aSSimon Glass }
3706c887b2aSSimon Glass }
3716c887b2aSSimon Glass
3726c887b2aSSimon Glass /* Figure out what functions we want to trace */
3736c887b2aSSimon Glass check_trace_config();
3746c887b2aSSimon Glass
3756c887b2aSSimon Glass warn("%d functions removed by linker, %ld code size\n",
3766c887b2aSSimon Glass not_found, removed_code_size);
3776c887b2aSSimon Glass }
3786c887b2aSSimon Glass
read_trace_config(FILE * fin)3796c887b2aSSimon Glass static int read_trace_config(FILE *fin)
3806c887b2aSSimon Glass {
3816c887b2aSSimon Glass char buff[200];
3826c887b2aSSimon Glass int linenum = 0;
3836c887b2aSSimon Glass struct trace_configline_info **tailp = &trace_config_head;
3846c887b2aSSimon Glass
3856c887b2aSSimon Glass while (fgets(buff, sizeof(buff), fin)) {
3866c887b2aSSimon Glass int len = strlen(buff);
3876c887b2aSSimon Glass struct trace_configline_info *line;
3886c887b2aSSimon Glass char *saveptr;
3896c887b2aSSimon Glass char *s, *tok;
3906c887b2aSSimon Glass int err;
3916c887b2aSSimon Glass
3926c887b2aSSimon Glass linenum++;
3936c887b2aSSimon Glass if (len && buff[len - 1] == '\n')
3946c887b2aSSimon Glass buff[len - 1] = '\0';
3956c887b2aSSimon Glass
3966c887b2aSSimon Glass /* skip blank lines and comments */
3976c887b2aSSimon Glass for (s = buff; *s == ' ' || *s == '\t'; s++)
3986c887b2aSSimon Glass ;
3996c887b2aSSimon Glass if (!*s || *s == '#')
4006c887b2aSSimon Glass continue;
4016c887b2aSSimon Glass
4026c887b2aSSimon Glass line = (struct trace_configline_info *)calloc(1,
4036c887b2aSSimon Glass sizeof(*line));
4046c887b2aSSimon Glass if (!line) {
4056c887b2aSSimon Glass error("Cannot allocate config line\n");
4066c887b2aSSimon Glass return -1;
4076c887b2aSSimon Glass }
4086c887b2aSSimon Glass
4096c887b2aSSimon Glass tok = strtok_r(s, " \t", &saveptr);
4106c887b2aSSimon Glass if (!tok) {
4116c887b2aSSimon Glass error("Invalid trace config data on line %d\n",
4126c887b2aSSimon Glass linenum);
4136c887b2aSSimon Glass return -1;
4146c887b2aSSimon Glass }
4156c887b2aSSimon Glass if (0 == strcmp(tok, "include-func")) {
4166c887b2aSSimon Glass line->type = TRACE_LINE_INCLUDE;
4176c887b2aSSimon Glass } else if (0 == strcmp(tok, "exclude-func")) {
4186c887b2aSSimon Glass line->type = TRACE_LINE_EXCLUDE;
4196c887b2aSSimon Glass } else {
4206c887b2aSSimon Glass error("Unknown command in trace config data line %d\n",
4216c887b2aSSimon Glass linenum);
4226c887b2aSSimon Glass return -1;
4236c887b2aSSimon Glass }
4246c887b2aSSimon Glass
4256c887b2aSSimon Glass tok = strtok_r(NULL, " \t", &saveptr);
4266c887b2aSSimon Glass if (!tok) {
4276c887b2aSSimon Glass error("Missing pattern in trace config data line %d\n",
4286c887b2aSSimon Glass linenum);
4296c887b2aSSimon Glass return -1;
4306c887b2aSSimon Glass }
4316c887b2aSSimon Glass
4326c887b2aSSimon Glass err = regcomp(&line->regex, tok, REG_NOSUB);
4336c887b2aSSimon Glass if (err) {
4341ca8f881SVincent Stehlé int r = regex_report_error(&line->regex, err,
4351ca8f881SVincent Stehlé "compile", tok);
4366c887b2aSSimon Glass free(line);
4371ca8f881SVincent Stehlé return r;
4386c887b2aSSimon Glass }
4396c887b2aSSimon Glass
4406c887b2aSSimon Glass /* link this new one to the end of the list */
4416c887b2aSSimon Glass line->name = strdup(tok);
4426c887b2aSSimon Glass line->next = NULL;
4436c887b2aSSimon Glass *tailp = line;
4446c887b2aSSimon Glass tailp = &line->next;
4456c887b2aSSimon Glass }
4466c887b2aSSimon Glass
4476c887b2aSSimon Glass if (!feof(fin)) {
4486c887b2aSSimon Glass error("Cannot read from trace config file at position %ld\n",
4496c887b2aSSimon Glass ftell(fin));
4506c887b2aSSimon Glass return -1;
4516c887b2aSSimon Glass }
4526c887b2aSSimon Glass return 0;
4536c887b2aSSimon Glass }
4546c887b2aSSimon Glass
read_trace_config_file(const char * fname)4556c887b2aSSimon Glass static int read_trace_config_file(const char *fname)
4566c887b2aSSimon Glass {
4576c887b2aSSimon Glass FILE *fin;
4586c887b2aSSimon Glass int err;
4596c887b2aSSimon Glass
4606c887b2aSSimon Glass fin = fopen(fname, "r");
4616c887b2aSSimon Glass if (!fin) {
4626c887b2aSSimon Glass error("Cannot open trace_config file '%s'\n", fname);
4636c887b2aSSimon Glass return -1;
4646c887b2aSSimon Glass }
4656c887b2aSSimon Glass err = read_trace_config(fin);
4666c887b2aSSimon Glass fclose(fin);
4676c887b2aSSimon Glass return err;
4686c887b2aSSimon Glass }
4696c887b2aSSimon Glass
out_func(ulong func_offset,int is_caller,const char * suffix)4706c887b2aSSimon Glass static void out_func(ulong func_offset, int is_caller, const char *suffix)
4716c887b2aSSimon Glass {
4726c887b2aSSimon Glass struct func_info *func;
4736c887b2aSSimon Glass
4746c887b2aSSimon Glass func = (is_caller ? find_caller_by_offset : find_func_by_offset)
4756c887b2aSSimon Glass (func_offset);
4766c887b2aSSimon Glass
4776c887b2aSSimon Glass if (func)
4786c887b2aSSimon Glass printf("%s%s", func->name, suffix);
4796c887b2aSSimon Glass else
4806c887b2aSSimon Glass printf("%lx%s", func_offset, suffix);
4816c887b2aSSimon Glass }
4826c887b2aSSimon Glass
4836c887b2aSSimon Glass /*
4846c887b2aSSimon Glass * # tracer: function
4856c887b2aSSimon Glass * #
4866c887b2aSSimon Glass * # TASK-PID CPU# TIMESTAMP FUNCTION
4876c887b2aSSimon Glass * # | | | | |
4886c887b2aSSimon Glass * # bash-4251 [01] 10152.583854: path_put <-path_walk
4896c887b2aSSimon Glass * # bash-4251 [01] 10152.583855: dput <-path_put
4906c887b2aSSimon Glass * # bash-4251 [01] 10152.583855: _atomic_dec_and_lock <-dput
4916c887b2aSSimon Glass */
make_ftrace(void)4926c887b2aSSimon Glass static int make_ftrace(void)
4936c887b2aSSimon Glass {
4946c887b2aSSimon Glass struct trace_call *call;
4956c887b2aSSimon Glass int missing_count = 0, skip_count = 0;
4966c887b2aSSimon Glass int i;
4976c887b2aSSimon Glass
4986c887b2aSSimon Glass printf("# tracer: ftrace\n"
4996c887b2aSSimon Glass "#\n"
5006c887b2aSSimon Glass "# TASK-PID CPU# TIMESTAMP FUNCTION\n"
5016c887b2aSSimon Glass "# | | | | |\n");
5026c887b2aSSimon Glass for (i = 0, call = call_list; i < call_count; i++, call++) {
5036c887b2aSSimon Glass struct func_info *func = find_func_by_offset(call->func);
5046c887b2aSSimon Glass ulong time = call->flags & FUNCF_TIMESTAMP_MASK;
5056c887b2aSSimon Glass
5066c887b2aSSimon Glass if (TRACE_CALL_TYPE(call) != FUNCF_ENTRY &&
5076c887b2aSSimon Glass TRACE_CALL_TYPE(call) != FUNCF_EXIT)
5086c887b2aSSimon Glass continue;
5096c887b2aSSimon Glass if (!func) {
5106c887b2aSSimon Glass warn("Cannot find function at %lx\n",
5116c887b2aSSimon Glass text_offset + call->func);
5126c887b2aSSimon Glass missing_count++;
5136c887b2aSSimon Glass continue;
5146c887b2aSSimon Glass }
5156c887b2aSSimon Glass
5166c887b2aSSimon Glass if (!(func->flags & FUNCF_TRACE)) {
5176c887b2aSSimon Glass debug("Funcion '%s' is excluded from trace\n",
5186c887b2aSSimon Glass func->name);
5196c887b2aSSimon Glass skip_count++;
5206c887b2aSSimon Glass continue;
5216c887b2aSSimon Glass }
5226c887b2aSSimon Glass
5236c887b2aSSimon Glass printf("%16s-%-5d [01] %lu.%06lu: ", "uboot", 1,
5246c887b2aSSimon Glass time / 1000000, time % 1000000);
5256c887b2aSSimon Glass
5266c887b2aSSimon Glass out_func(call->func, 0, " <- ");
5276c887b2aSSimon Glass out_func(call->caller, 1, "\n");
5286c887b2aSSimon Glass }
5296c887b2aSSimon Glass info("ftrace: %d functions not found, %d excluded\n", missing_count,
5306c887b2aSSimon Glass skip_count);
5316c887b2aSSimon Glass
5326c887b2aSSimon Glass return 0;
5336c887b2aSSimon Glass }
5346c887b2aSSimon Glass
prof_tool(int argc,char * const argv[],const char * prof_fname,const char * map_fname,const char * trace_config_fname)5356c887b2aSSimon Glass static int prof_tool(int argc, char * const argv[],
5366c887b2aSSimon Glass const char *prof_fname, const char *map_fname,
5376c887b2aSSimon Glass const char *trace_config_fname)
5386c887b2aSSimon Glass {
5396c887b2aSSimon Glass int err = 0;
5406c887b2aSSimon Glass
5416c887b2aSSimon Glass if (read_map_file(map_fname))
5426c887b2aSSimon Glass return -1;
5436c887b2aSSimon Glass if (prof_fname && read_profile_file(prof_fname))
5446c887b2aSSimon Glass return -1;
5456c887b2aSSimon Glass if (trace_config_fname && read_trace_config_file(trace_config_fname))
5466c887b2aSSimon Glass return -1;
5476c887b2aSSimon Glass
5486c887b2aSSimon Glass check_functions();
5496c887b2aSSimon Glass
5506c887b2aSSimon Glass for (; argc; argc--, argv++) {
5516c887b2aSSimon Glass const char *cmd = *argv;
5526c887b2aSSimon Glass
5536c887b2aSSimon Glass if (0 == strcmp(cmd, "dump-ftrace"))
5546c887b2aSSimon Glass err = make_ftrace();
5556c887b2aSSimon Glass else
5566c887b2aSSimon Glass warn("Unknown command '%s'\n", cmd);
5576c887b2aSSimon Glass }
5586c887b2aSSimon Glass
5596c887b2aSSimon Glass return err;
5606c887b2aSSimon Glass }
5616c887b2aSSimon Glass
main(int argc,char * argv[])5626c887b2aSSimon Glass int main(int argc, char *argv[])
5636c887b2aSSimon Glass {
5646c887b2aSSimon Glass const char *map_fname = "System.map";
5656c887b2aSSimon Glass const char *prof_fname = NULL;
5666c887b2aSSimon Glass const char *trace_config_fname = NULL;
5676c887b2aSSimon Glass int opt;
5686c887b2aSSimon Glass
5696c887b2aSSimon Glass verbose = 2;
5706c887b2aSSimon Glass while ((opt = getopt(argc, argv, "m:p:t:v:")) != -1) {
5716c887b2aSSimon Glass switch (opt) {
5726c887b2aSSimon Glass case 'm':
5736c887b2aSSimon Glass map_fname = optarg;
5746c887b2aSSimon Glass break;
5756c887b2aSSimon Glass
5766c887b2aSSimon Glass case 'p':
5776c887b2aSSimon Glass prof_fname = optarg;
5786c887b2aSSimon Glass break;
5796c887b2aSSimon Glass
5806c887b2aSSimon Glass case 't':
5816c887b2aSSimon Glass trace_config_fname = optarg;
5826c887b2aSSimon Glass break;
5836c887b2aSSimon Glass
5846c887b2aSSimon Glass case 'v':
5856c887b2aSSimon Glass verbose = atoi(optarg);
5866c887b2aSSimon Glass break;
5876c887b2aSSimon Glass
5886c887b2aSSimon Glass default:
5896c887b2aSSimon Glass usage();
5906c887b2aSSimon Glass }
5916c887b2aSSimon Glass }
5926c887b2aSSimon Glass argc -= optind; argv += optind;
5936c887b2aSSimon Glass if (argc < 1)
5946c887b2aSSimon Glass usage();
5956c887b2aSSimon Glass
5966c887b2aSSimon Glass debug("Debug enabled\n");
5976c887b2aSSimon Glass return prof_tool(argc, argv, prof_fname, map_fname,
5986c887b2aSSimon Glass trace_config_fname);
5996c887b2aSSimon Glass }
600