150656eecSMasami Hiramatsu /* 250656eecSMasami Hiramatsu * probe-event.c : perf-probe definition to kprobe_events format converter 350656eecSMasami Hiramatsu * 450656eecSMasami Hiramatsu * Written by Masami Hiramatsu <mhiramat@redhat.com> 550656eecSMasami Hiramatsu * 650656eecSMasami Hiramatsu * This program is free software; you can redistribute it and/or modify 750656eecSMasami Hiramatsu * it under the terms of the GNU General Public License as published by 850656eecSMasami Hiramatsu * the Free Software Foundation; either version 2 of the License, or 950656eecSMasami Hiramatsu * (at your option) any later version. 1050656eecSMasami Hiramatsu * 1150656eecSMasami Hiramatsu * This program is distributed in the hope that it will be useful, 1250656eecSMasami Hiramatsu * but WITHOUT ANY WARRANTY; without even the implied warranty of 1350656eecSMasami Hiramatsu * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1450656eecSMasami Hiramatsu * GNU General Public License for more details. 1550656eecSMasami Hiramatsu * 1650656eecSMasami Hiramatsu * You should have received a copy of the GNU General Public License 1750656eecSMasami Hiramatsu * along with this program; if not, write to the Free Software 1850656eecSMasami Hiramatsu * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 1950656eecSMasami Hiramatsu * 2050656eecSMasami Hiramatsu */ 2150656eecSMasami Hiramatsu 2250656eecSMasami Hiramatsu #define _GNU_SOURCE 2350656eecSMasami Hiramatsu #include <sys/utsname.h> 2450656eecSMasami Hiramatsu #include <sys/types.h> 2550656eecSMasami Hiramatsu #include <sys/stat.h> 2650656eecSMasami Hiramatsu #include <fcntl.h> 2750656eecSMasami Hiramatsu #include <errno.h> 2850656eecSMasami Hiramatsu #include <stdio.h> 2950656eecSMasami Hiramatsu #include <unistd.h> 3050656eecSMasami Hiramatsu #include <stdlib.h> 3150656eecSMasami Hiramatsu #include <string.h> 324de189feSMasami Hiramatsu #include <stdarg.h> 334de189feSMasami Hiramatsu #include <limits.h> 3450656eecSMasami Hiramatsu 3550656eecSMasami Hiramatsu #undef _GNU_SOURCE 36*31facc5fSMasami Hiramatsu #include "util.h" 3750656eecSMasami Hiramatsu #include "event.h" 38e1c01d61SMasami Hiramatsu #include "string.h" 394de189feSMasami Hiramatsu #include "strlist.h" 4050656eecSMasami Hiramatsu #include "debug.h" 4172041334SMasami Hiramatsu #include "cache.h" 42631c9defSMasami Hiramatsu #include "color.h" 4350656eecSMasami Hiramatsu #include "parse-events.h" /* For debugfs_path */ 4450656eecSMasami Hiramatsu #include "probe-event.h" 4550656eecSMasami Hiramatsu 4650656eecSMasami Hiramatsu #define MAX_CMDLEN 256 4750656eecSMasami Hiramatsu #define MAX_PROBE_ARGS 128 4850656eecSMasami Hiramatsu #define PERFPROBE_GROUP "probe" 4950656eecSMasami Hiramatsu 5050656eecSMasami Hiramatsu #define semantic_error(msg ...) die("Semantic error :" msg) 5150656eecSMasami Hiramatsu 524de189feSMasami Hiramatsu /* If there is no space to write, returns -E2BIG. */ 534de189feSMasami Hiramatsu static int e_snprintf(char *str, size_t size, const char *format, ...) 5484988450SMasami Hiramatsu __attribute__((format(printf, 3, 4))); 5584988450SMasami Hiramatsu 5684988450SMasami Hiramatsu static int e_snprintf(char *str, size_t size, const char *format, ...) 574de189feSMasami Hiramatsu { 584de189feSMasami Hiramatsu int ret; 594de189feSMasami Hiramatsu va_list ap; 604de189feSMasami Hiramatsu va_start(ap, format); 614de189feSMasami Hiramatsu ret = vsnprintf(str, size, format, ap); 624de189feSMasami Hiramatsu va_end(ap); 634de189feSMasami Hiramatsu if (ret >= (int)size) 644de189feSMasami Hiramatsu ret = -E2BIG; 654de189feSMasami Hiramatsu return ret; 664de189feSMasami Hiramatsu } 674de189feSMasami Hiramatsu 68631c9defSMasami Hiramatsu void parse_line_range_desc(const char *arg, struct line_range *lr) 69631c9defSMasami Hiramatsu { 70631c9defSMasami Hiramatsu const char *ptr; 71631c9defSMasami Hiramatsu char *tmp; 72631c9defSMasami Hiramatsu /* 73631c9defSMasami Hiramatsu * <Syntax> 74631c9defSMasami Hiramatsu * SRC:SLN[+NUM|-ELN] 75631c9defSMasami Hiramatsu * FUNC[:SLN[+NUM|-ELN]] 76631c9defSMasami Hiramatsu */ 77631c9defSMasami Hiramatsu ptr = strchr(arg, ':'); 78631c9defSMasami Hiramatsu if (ptr) { 79631c9defSMasami Hiramatsu lr->start = (unsigned int)strtoul(ptr + 1, &tmp, 0); 80631c9defSMasami Hiramatsu if (*tmp == '+') 81631c9defSMasami Hiramatsu lr->end = lr->start + (unsigned int)strtoul(tmp + 1, 82631c9defSMasami Hiramatsu &tmp, 0); 83631c9defSMasami Hiramatsu else if (*tmp == '-') 84631c9defSMasami Hiramatsu lr->end = (unsigned int)strtoul(tmp + 1, &tmp, 0); 85631c9defSMasami Hiramatsu else 86631c9defSMasami Hiramatsu lr->end = 0; 87631c9defSMasami Hiramatsu pr_debug("Line range is %u to %u\n", lr->start, lr->end); 88631c9defSMasami Hiramatsu if (lr->end && lr->start > lr->end) 89631c9defSMasami Hiramatsu semantic_error("Start line must be smaller" 90631c9defSMasami Hiramatsu " than end line."); 91631c9defSMasami Hiramatsu if (*tmp != '\0') 92631c9defSMasami Hiramatsu semantic_error("Tailing with invalid character '%d'.", 93631c9defSMasami Hiramatsu *tmp); 94*31facc5fSMasami Hiramatsu tmp = xstrndup(arg, (ptr - arg)); 95631c9defSMasami Hiramatsu } else 96*31facc5fSMasami Hiramatsu tmp = xstrdup(arg); 97631c9defSMasami Hiramatsu 98631c9defSMasami Hiramatsu if (strchr(tmp, '.')) 99631c9defSMasami Hiramatsu lr->file = tmp; 100631c9defSMasami Hiramatsu else 101631c9defSMasami Hiramatsu lr->function = tmp; 102631c9defSMasami Hiramatsu } 103631c9defSMasami Hiramatsu 104b7702a21SMasami Hiramatsu /* Check the name is good for event/group */ 105b7702a21SMasami Hiramatsu static bool check_event_name(const char *name) 106b7702a21SMasami Hiramatsu { 107b7702a21SMasami Hiramatsu if (!isalpha(*name) && *name != '_') 108b7702a21SMasami Hiramatsu return false; 109b7702a21SMasami Hiramatsu while (*++name != '\0') { 110b7702a21SMasami Hiramatsu if (!isalpha(*name) && !isdigit(*name) && *name != '_') 111b7702a21SMasami Hiramatsu return false; 112b7702a21SMasami Hiramatsu } 113b7702a21SMasami Hiramatsu return true; 114b7702a21SMasami Hiramatsu } 115b7702a21SMasami Hiramatsu 11650656eecSMasami Hiramatsu /* Parse probepoint definition. */ 11750656eecSMasami Hiramatsu static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp) 11850656eecSMasami Hiramatsu { 11950656eecSMasami Hiramatsu char *ptr, *tmp; 12050656eecSMasami Hiramatsu char c, nc = 0; 12150656eecSMasami Hiramatsu /* 12250656eecSMasami Hiramatsu * <Syntax> 1232a9c8c36SMasami Hiramatsu * perf probe [EVENT=]SRC[:LN|;PTN] 1242a9c8c36SMasami Hiramatsu * perf probe [EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT] 125af663d75SMasami Hiramatsu * 126af663d75SMasami Hiramatsu * TODO:Group name support 12750656eecSMasami Hiramatsu */ 12850656eecSMasami Hiramatsu 1292a9c8c36SMasami Hiramatsu ptr = strpbrk(arg, ";=@+%"); 1302a9c8c36SMasami Hiramatsu if (ptr && *ptr == '=') { /* Event name */ 131af663d75SMasami Hiramatsu *ptr = '\0'; 132af663d75SMasami Hiramatsu tmp = ptr + 1; 133af663d75SMasami Hiramatsu ptr = strchr(arg, ':'); 134af663d75SMasami Hiramatsu if (ptr) /* Group name is not supported yet. */ 135af663d75SMasami Hiramatsu semantic_error("Group name is not supported yet."); 136b7702a21SMasami Hiramatsu if (!check_event_name(arg)) 137b7702a21SMasami Hiramatsu semantic_error("%s is bad for event name -it must " 138b7702a21SMasami Hiramatsu "follow C symbol-naming rule.", arg); 139*31facc5fSMasami Hiramatsu pp->event = xstrdup(arg); 140af663d75SMasami Hiramatsu arg = tmp; 141af663d75SMasami Hiramatsu } 142af663d75SMasami Hiramatsu 1432a9c8c36SMasami Hiramatsu ptr = strpbrk(arg, ";:+@%"); 14450656eecSMasami Hiramatsu if (ptr) { 14550656eecSMasami Hiramatsu nc = *ptr; 14650656eecSMasami Hiramatsu *ptr++ = '\0'; 14750656eecSMasami Hiramatsu } 14850656eecSMasami Hiramatsu 14950656eecSMasami Hiramatsu /* Check arg is function or file and copy it */ 15050656eecSMasami Hiramatsu if (strchr(arg, '.')) /* File */ 151*31facc5fSMasami Hiramatsu pp->file = xstrdup(arg); 15250656eecSMasami Hiramatsu else /* Function */ 153*31facc5fSMasami Hiramatsu pp->function = xstrdup(arg); 15450656eecSMasami Hiramatsu 15550656eecSMasami Hiramatsu /* Parse other options */ 15650656eecSMasami Hiramatsu while (ptr) { 15750656eecSMasami Hiramatsu arg = ptr; 15850656eecSMasami Hiramatsu c = nc; 1592a9c8c36SMasami Hiramatsu if (c == ';') { /* Lazy pattern must be the last part */ 160*31facc5fSMasami Hiramatsu pp->lazy_line = xstrdup(arg); 1612a9c8c36SMasami Hiramatsu break; 1622a9c8c36SMasami Hiramatsu } 1632a9c8c36SMasami Hiramatsu ptr = strpbrk(arg, ";:+@%"); 16450656eecSMasami Hiramatsu if (ptr) { 16550656eecSMasami Hiramatsu nc = *ptr; 16650656eecSMasami Hiramatsu *ptr++ = '\0'; 16750656eecSMasami Hiramatsu } 16850656eecSMasami Hiramatsu switch (c) { 16950656eecSMasami Hiramatsu case ':': /* Line number */ 17050656eecSMasami Hiramatsu pp->line = strtoul(arg, &tmp, 0); 17150656eecSMasami Hiramatsu if (*tmp != '\0') 1722a9c8c36SMasami Hiramatsu semantic_error("There is non-digit char" 17350656eecSMasami Hiramatsu " in line number."); 17450656eecSMasami Hiramatsu break; 17550656eecSMasami Hiramatsu case '+': /* Byte offset from a symbol */ 17650656eecSMasami Hiramatsu pp->offset = strtoul(arg, &tmp, 0); 17750656eecSMasami Hiramatsu if (*tmp != '\0') 1782a9c8c36SMasami Hiramatsu semantic_error("There is non-digit character" 17950656eecSMasami Hiramatsu " in offset."); 18050656eecSMasami Hiramatsu break; 18150656eecSMasami Hiramatsu case '@': /* File name */ 18250656eecSMasami Hiramatsu if (pp->file) 18350656eecSMasami Hiramatsu semantic_error("SRC@SRC is not allowed."); 184*31facc5fSMasami Hiramatsu pp->file = xstrdup(arg); 18550656eecSMasami Hiramatsu break; 18650656eecSMasami Hiramatsu case '%': /* Probe places */ 18750656eecSMasami Hiramatsu if (strcmp(arg, "return") == 0) { 18850656eecSMasami Hiramatsu pp->retprobe = 1; 18950656eecSMasami Hiramatsu } else /* Others not supported yet */ 19050656eecSMasami Hiramatsu semantic_error("%%%s is not supported.", arg); 19150656eecSMasami Hiramatsu break; 19250656eecSMasami Hiramatsu default: 19350656eecSMasami Hiramatsu DIE_IF("Program has a bug."); 19450656eecSMasami Hiramatsu break; 19550656eecSMasami Hiramatsu } 19650656eecSMasami Hiramatsu } 19750656eecSMasami Hiramatsu 19850656eecSMasami Hiramatsu /* Exclusion check */ 1992a9c8c36SMasami Hiramatsu if (pp->lazy_line && pp->line) 2002a9c8c36SMasami Hiramatsu semantic_error("Lazy pattern can't be used with line number."); 2012a9c8c36SMasami Hiramatsu 2022a9c8c36SMasami Hiramatsu if (pp->lazy_line && pp->offset) 2032a9c8c36SMasami Hiramatsu semantic_error("Lazy pattern can't be used with offset."); 2042a9c8c36SMasami Hiramatsu 20550656eecSMasami Hiramatsu if (pp->line && pp->offset) 20650656eecSMasami Hiramatsu semantic_error("Offset can't be used with line number."); 20750656eecSMasami Hiramatsu 2082a9c8c36SMasami Hiramatsu if (!pp->line && !pp->lazy_line && pp->file && !pp->function) 2092a9c8c36SMasami Hiramatsu semantic_error("File always requires line number or " 2102a9c8c36SMasami Hiramatsu "lazy pattern."); 21150656eecSMasami Hiramatsu 21250656eecSMasami Hiramatsu if (pp->offset && !pp->function) 21350656eecSMasami Hiramatsu semantic_error("Offset requires an entry function."); 21450656eecSMasami Hiramatsu 21550656eecSMasami Hiramatsu if (pp->retprobe && !pp->function) 21650656eecSMasami Hiramatsu semantic_error("Return probe requires an entry function."); 21750656eecSMasami Hiramatsu 2182a9c8c36SMasami Hiramatsu if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) 2192a9c8c36SMasami Hiramatsu semantic_error("Offset/Line/Lazy pattern can't be used with " 2202a9c8c36SMasami Hiramatsu "return probe."); 22150656eecSMasami Hiramatsu 2222a9c8c36SMasami Hiramatsu pr_debug("symbol:%s file:%s line:%d offset:%d return:%d lazy:%s\n", 2232a9c8c36SMasami Hiramatsu pp->function, pp->file, pp->line, pp->offset, pp->retprobe, 2242a9c8c36SMasami Hiramatsu pp->lazy_line); 22550656eecSMasami Hiramatsu } 22650656eecSMasami Hiramatsu 22750656eecSMasami Hiramatsu /* Parse perf-probe event definition */ 228fac13fd5SMasami Hiramatsu void parse_perf_probe_event(const char *str, struct probe_point *pp, 229fac13fd5SMasami Hiramatsu bool *need_dwarf) 23050656eecSMasami Hiramatsu { 231e1c01d61SMasami Hiramatsu char **argv; 232fac13fd5SMasami Hiramatsu int argc, i; 233fac13fd5SMasami Hiramatsu 234fac13fd5SMasami Hiramatsu *need_dwarf = false; 23550656eecSMasami Hiramatsu 236e1c01d61SMasami Hiramatsu argv = argv_split(str, &argc); 237e1c01d61SMasami Hiramatsu if (!argv) 238e1c01d61SMasami Hiramatsu die("argv_split failed."); 239e1c01d61SMasami Hiramatsu if (argc > MAX_PROBE_ARGS + 1) 24050656eecSMasami Hiramatsu semantic_error("Too many arguments"); 24150656eecSMasami Hiramatsu 24250656eecSMasami Hiramatsu /* Parse probe point */ 24350656eecSMasami Hiramatsu parse_perf_probe_probepoint(argv[0], pp); 244fc6ceea0SMasami Hiramatsu if (pp->file || pp->line || pp->lazy_line) 245fac13fd5SMasami Hiramatsu *need_dwarf = true; 24650656eecSMasami Hiramatsu 247e1c01d61SMasami Hiramatsu /* Copy arguments and ensure return probe has no C argument */ 24850656eecSMasami Hiramatsu pp->nr_args = argc - 1; 249*31facc5fSMasami Hiramatsu pp->args = xzalloc(sizeof(char *) * pp->nr_args); 250e1c01d61SMasami Hiramatsu for (i = 0; i < pp->nr_args; i++) { 251*31facc5fSMasami Hiramatsu pp->args[i] = xstrdup(argv[i + 1]); 25250656eecSMasami Hiramatsu if (is_c_varname(pp->args[i])) { 25350656eecSMasami Hiramatsu if (pp->retprobe) 25450656eecSMasami Hiramatsu semantic_error("You can't specify local" 25550656eecSMasami Hiramatsu " variable for kretprobe"); 256fac13fd5SMasami Hiramatsu *need_dwarf = true; 25750656eecSMasami Hiramatsu } 258e1c01d61SMasami Hiramatsu } 25950656eecSMasami Hiramatsu 260e1c01d61SMasami Hiramatsu argv_free(argv); 26150656eecSMasami Hiramatsu } 26250656eecSMasami Hiramatsu 2634de189feSMasami Hiramatsu /* Parse kprobe_events event into struct probe_point */ 264af663d75SMasami Hiramatsu void parse_trace_kprobe_event(const char *str, struct probe_point *pp) 2654de189feSMasami Hiramatsu { 2664de189feSMasami Hiramatsu char pr; 2674de189feSMasami Hiramatsu char *p; 2684de189feSMasami Hiramatsu int ret, i, argc; 2694de189feSMasami Hiramatsu char **argv; 2704de189feSMasami Hiramatsu 2714de189feSMasami Hiramatsu pr_debug("Parsing kprobe_events: %s\n", str); 2724de189feSMasami Hiramatsu argv = argv_split(str, &argc); 2734de189feSMasami Hiramatsu if (!argv) 2744de189feSMasami Hiramatsu die("argv_split failed."); 2754de189feSMasami Hiramatsu if (argc < 2) 2764de189feSMasami Hiramatsu semantic_error("Too less arguments."); 2774de189feSMasami Hiramatsu 2784de189feSMasami Hiramatsu /* Scan event and group name. */ 27993aaa45aSLiming Wang ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]", 280af663d75SMasami Hiramatsu &pr, (float *)(void *)&pp->group, 281af663d75SMasami Hiramatsu (float *)(void *)&pp->event); 2824de189feSMasami Hiramatsu if (ret != 3) 2834de189feSMasami Hiramatsu semantic_error("Failed to parse event name: %s", argv[0]); 284af663d75SMasami Hiramatsu pr_debug("Group:%s Event:%s probe:%c\n", pp->group, pp->event, pr); 2854de189feSMasami Hiramatsu 2864de189feSMasami Hiramatsu pp->retprobe = (pr == 'r'); 2874de189feSMasami Hiramatsu 2884de189feSMasami Hiramatsu /* Scan function name and offset */ 289af663d75SMasami Hiramatsu ret = sscanf(argv[1], "%a[^+]+%d", (float *)(void *)&pp->function, 290af663d75SMasami Hiramatsu &pp->offset); 2914de189feSMasami Hiramatsu if (ret == 1) 2924de189feSMasami Hiramatsu pp->offset = 0; 2934de189feSMasami Hiramatsu 2944de189feSMasami Hiramatsu /* kprobe_events doesn't have this information */ 2954de189feSMasami Hiramatsu pp->line = 0; 2964de189feSMasami Hiramatsu pp->file = NULL; 2974de189feSMasami Hiramatsu 2984de189feSMasami Hiramatsu pp->nr_args = argc - 2; 299*31facc5fSMasami Hiramatsu pp->args = xzalloc(sizeof(char *) * pp->nr_args); 3004de189feSMasami Hiramatsu for (i = 0; i < pp->nr_args; i++) { 3014de189feSMasami Hiramatsu p = strchr(argv[i + 2], '='); 3024de189feSMasami Hiramatsu if (p) /* We don't need which register is assigned. */ 3034de189feSMasami Hiramatsu *p = '\0'; 304*31facc5fSMasami Hiramatsu pp->args[i] = xstrdup(argv[i + 2]); 3054de189feSMasami Hiramatsu } 3064de189feSMasami Hiramatsu 3074de189feSMasami Hiramatsu argv_free(argv); 3084de189feSMasami Hiramatsu } 3094de189feSMasami Hiramatsu 3107ef17aafSMasami Hiramatsu /* Synthesize only probe point (not argument) */ 3117ef17aafSMasami Hiramatsu int synthesize_perf_probe_point(struct probe_point *pp) 31250656eecSMasami Hiramatsu { 31350656eecSMasami Hiramatsu char *buf; 3144de189feSMasami Hiramatsu char offs[64] = "", line[64] = ""; 3157ef17aafSMasami Hiramatsu int ret; 31650656eecSMasami Hiramatsu 317*31facc5fSMasami Hiramatsu pp->probes[0] = buf = xzalloc(MAX_CMDLEN); 318388c3aabSMasami Hiramatsu pp->found = 1; 3194de189feSMasami Hiramatsu if (pp->offset) { 3204de189feSMasami Hiramatsu ret = e_snprintf(offs, 64, "+%d", pp->offset); 3214de189feSMasami Hiramatsu if (ret <= 0) 3224de189feSMasami Hiramatsu goto error; 3234de189feSMasami Hiramatsu } 3244de189feSMasami Hiramatsu if (pp->line) { 3254de189feSMasami Hiramatsu ret = e_snprintf(line, 64, ":%d", pp->line); 3264de189feSMasami Hiramatsu if (ret <= 0) 3274de189feSMasami Hiramatsu goto error; 3284de189feSMasami Hiramatsu } 3294de189feSMasami Hiramatsu 3304de189feSMasami Hiramatsu if (pp->function) 3314de189feSMasami Hiramatsu ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->function, 3324de189feSMasami Hiramatsu offs, pp->retprobe ? "%return" : "", line); 3334de189feSMasami Hiramatsu else 33484988450SMasami Hiramatsu ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", pp->file, line); 3357ef17aafSMasami Hiramatsu if (ret <= 0) { 3367ef17aafSMasami Hiramatsu error: 3377ef17aafSMasami Hiramatsu free(pp->probes[0]); 3387ef17aafSMasami Hiramatsu pp->probes[0] = NULL; 339388c3aabSMasami Hiramatsu pp->found = 0; 3407ef17aafSMasami Hiramatsu } 3417ef17aafSMasami Hiramatsu return ret; 3427ef17aafSMasami Hiramatsu } 34350656eecSMasami Hiramatsu 3447ef17aafSMasami Hiramatsu int synthesize_perf_probe_event(struct probe_point *pp) 3457ef17aafSMasami Hiramatsu { 3467ef17aafSMasami Hiramatsu char *buf; 3477ef17aafSMasami Hiramatsu int i, len, ret; 3487ef17aafSMasami Hiramatsu 3497ef17aafSMasami Hiramatsu len = synthesize_perf_probe_point(pp); 3507ef17aafSMasami Hiramatsu if (len < 0) 3517ef17aafSMasami Hiramatsu return 0; 3527ef17aafSMasami Hiramatsu 3537ef17aafSMasami Hiramatsu buf = pp->probes[0]; 35450656eecSMasami Hiramatsu for (i = 0; i < pp->nr_args; i++) { 3554de189feSMasami Hiramatsu ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s", 35650656eecSMasami Hiramatsu pp->args[i]); 3574de189feSMasami Hiramatsu if (ret <= 0) 35850656eecSMasami Hiramatsu goto error; 35950656eecSMasami Hiramatsu len += ret; 36050656eecSMasami Hiramatsu } 36150656eecSMasami Hiramatsu pp->found = 1; 36250656eecSMasami Hiramatsu 36350656eecSMasami Hiramatsu return pp->found; 36450656eecSMasami Hiramatsu error: 36550656eecSMasami Hiramatsu free(pp->probes[0]); 3667ef17aafSMasami Hiramatsu pp->probes[0] = NULL; 36750656eecSMasami Hiramatsu 36850656eecSMasami Hiramatsu return ret; 36950656eecSMasami Hiramatsu } 37050656eecSMasami Hiramatsu 3714de189feSMasami Hiramatsu int synthesize_trace_kprobe_event(struct probe_point *pp) 3724de189feSMasami Hiramatsu { 3734de189feSMasami Hiramatsu char *buf; 3744de189feSMasami Hiramatsu int i, len, ret; 3754de189feSMasami Hiramatsu 376*31facc5fSMasami Hiramatsu pp->probes[0] = buf = xzalloc(MAX_CMDLEN); 3774de189feSMasami Hiramatsu ret = e_snprintf(buf, MAX_CMDLEN, "%s+%d", pp->function, pp->offset); 3784de189feSMasami Hiramatsu if (ret <= 0) 3794de189feSMasami Hiramatsu goto error; 3804de189feSMasami Hiramatsu len = ret; 3814de189feSMasami Hiramatsu 3824de189feSMasami Hiramatsu for (i = 0; i < pp->nr_args; i++) { 3834de189feSMasami Hiramatsu ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s", 3844de189feSMasami Hiramatsu pp->args[i]); 3854de189feSMasami Hiramatsu if (ret <= 0) 3864de189feSMasami Hiramatsu goto error; 3874de189feSMasami Hiramatsu len += ret; 3884de189feSMasami Hiramatsu } 3894de189feSMasami Hiramatsu pp->found = 1; 3904de189feSMasami Hiramatsu 3914de189feSMasami Hiramatsu return pp->found; 3924de189feSMasami Hiramatsu error: 3934de189feSMasami Hiramatsu free(pp->probes[0]); 3947ef17aafSMasami Hiramatsu pp->probes[0] = NULL; 3954de189feSMasami Hiramatsu 3964de189feSMasami Hiramatsu return ret; 3974de189feSMasami Hiramatsu } 3984de189feSMasami Hiramatsu 3994de189feSMasami Hiramatsu static int open_kprobe_events(int flags, int mode) 4004de189feSMasami Hiramatsu { 4014de189feSMasami Hiramatsu char buf[PATH_MAX]; 4024de189feSMasami Hiramatsu int ret; 4034de189feSMasami Hiramatsu 4044de189feSMasami Hiramatsu ret = e_snprintf(buf, PATH_MAX, "%s/../kprobe_events", debugfs_path); 4054de189feSMasami Hiramatsu if (ret < 0) 4064de189feSMasami Hiramatsu die("Failed to make kprobe_events path."); 4074de189feSMasami Hiramatsu 4084de189feSMasami Hiramatsu ret = open(buf, flags, mode); 4094de189feSMasami Hiramatsu if (ret < 0) { 4104de189feSMasami Hiramatsu if (errno == ENOENT) 4114de189feSMasami Hiramatsu die("kprobe_events file does not exist -" 41263bbd5e2SLiming Wang " please rebuild with CONFIG_KPROBE_EVENT."); 4134de189feSMasami Hiramatsu else 4144de189feSMasami Hiramatsu die("Could not open kprobe_events file: %s", 4154de189feSMasami Hiramatsu strerror(errno)); 4164de189feSMasami Hiramatsu } 4174de189feSMasami Hiramatsu return ret; 4184de189feSMasami Hiramatsu } 4194de189feSMasami Hiramatsu 4204de189feSMasami Hiramatsu /* Get raw string list of current kprobe_events */ 4214de189feSMasami Hiramatsu static struct strlist *get_trace_kprobe_event_rawlist(int fd) 4224de189feSMasami Hiramatsu { 4234de189feSMasami Hiramatsu int ret, idx; 4244de189feSMasami Hiramatsu FILE *fp; 4254de189feSMasami Hiramatsu char buf[MAX_CMDLEN]; 4264de189feSMasami Hiramatsu char *p; 4274de189feSMasami Hiramatsu struct strlist *sl; 4284de189feSMasami Hiramatsu 4294de189feSMasami Hiramatsu sl = strlist__new(true, NULL); 4304de189feSMasami Hiramatsu 4314de189feSMasami Hiramatsu fp = fdopen(dup(fd), "r"); 4324de189feSMasami Hiramatsu while (!feof(fp)) { 4334de189feSMasami Hiramatsu p = fgets(buf, MAX_CMDLEN, fp); 4344de189feSMasami Hiramatsu if (!p) 4354de189feSMasami Hiramatsu break; 4364de189feSMasami Hiramatsu 4374de189feSMasami Hiramatsu idx = strlen(p) - 1; 4384de189feSMasami Hiramatsu if (p[idx] == '\n') 4394de189feSMasami Hiramatsu p[idx] = '\0'; 4404de189feSMasami Hiramatsu ret = strlist__add(sl, buf); 4414de189feSMasami Hiramatsu if (ret < 0) 4424de189feSMasami Hiramatsu die("strlist__add failed: %s", strerror(-ret)); 4434de189feSMasami Hiramatsu } 4444de189feSMasami Hiramatsu fclose(fp); 4454de189feSMasami Hiramatsu 4464de189feSMasami Hiramatsu return sl; 4474de189feSMasami Hiramatsu } 4484de189feSMasami Hiramatsu 4494de189feSMasami Hiramatsu /* Free and zero clear probe_point */ 4504de189feSMasami Hiramatsu static void clear_probe_point(struct probe_point *pp) 4514de189feSMasami Hiramatsu { 4524de189feSMasami Hiramatsu int i; 4534de189feSMasami Hiramatsu 454af663d75SMasami Hiramatsu if (pp->event) 455af663d75SMasami Hiramatsu free(pp->event); 456af663d75SMasami Hiramatsu if (pp->group) 457af663d75SMasami Hiramatsu free(pp->group); 4584de189feSMasami Hiramatsu if (pp->function) 4594de189feSMasami Hiramatsu free(pp->function); 4604de189feSMasami Hiramatsu if (pp->file) 4614de189feSMasami Hiramatsu free(pp->file); 4622a9c8c36SMasami Hiramatsu if (pp->lazy_line) 4632a9c8c36SMasami Hiramatsu free(pp->lazy_line); 4644de189feSMasami Hiramatsu for (i = 0; i < pp->nr_args; i++) 4654de189feSMasami Hiramatsu free(pp->args[i]); 4664de189feSMasami Hiramatsu if (pp->args) 4674de189feSMasami Hiramatsu free(pp->args); 4684de189feSMasami Hiramatsu for (i = 0; i < pp->found; i++) 4694de189feSMasami Hiramatsu free(pp->probes[i]); 4705660ce34SJulia Lawall memset(pp, 0, sizeof(*pp)); 4714de189feSMasami Hiramatsu } 4724de189feSMasami Hiramatsu 473278498d4SMasami Hiramatsu /* Show an event */ 474af663d75SMasami Hiramatsu static void show_perf_probe_event(const char *event, const char *place, 475af663d75SMasami Hiramatsu struct probe_point *pp) 476278498d4SMasami Hiramatsu { 4777e990a51SMasami Hiramatsu int i, ret; 478278498d4SMasami Hiramatsu char buf[128]; 479278498d4SMasami Hiramatsu 480af663d75SMasami Hiramatsu ret = e_snprintf(buf, 128, "%s:%s", pp->group, event); 4817e990a51SMasami Hiramatsu if (ret < 0) 4827e990a51SMasami Hiramatsu die("Failed to copy event: %s", strerror(-ret)); 483278498d4SMasami Hiramatsu printf(" %-40s (on %s", buf, place); 484278498d4SMasami Hiramatsu 485278498d4SMasami Hiramatsu if (pp->nr_args > 0) { 486278498d4SMasami Hiramatsu printf(" with"); 487278498d4SMasami Hiramatsu for (i = 0; i < pp->nr_args; i++) 488278498d4SMasami Hiramatsu printf(" %s", pp->args[i]); 489278498d4SMasami Hiramatsu } 490278498d4SMasami Hiramatsu printf(")\n"); 491278498d4SMasami Hiramatsu } 492278498d4SMasami Hiramatsu 4934de189feSMasami Hiramatsu /* List up current perf-probe events */ 4944de189feSMasami Hiramatsu void show_perf_probe_events(void) 4954de189feSMasami Hiramatsu { 4967ef17aafSMasami Hiramatsu int fd; 4974de189feSMasami Hiramatsu struct probe_point pp; 4984de189feSMasami Hiramatsu struct strlist *rawlist; 4994de189feSMasami Hiramatsu struct str_node *ent; 5004de189feSMasami Hiramatsu 50172041334SMasami Hiramatsu setup_pager(); 502388c3aabSMasami Hiramatsu memset(&pp, 0, sizeof(pp)); 50372041334SMasami Hiramatsu 5044de189feSMasami Hiramatsu fd = open_kprobe_events(O_RDONLY, 0); 5054de189feSMasami Hiramatsu rawlist = get_trace_kprobe_event_rawlist(fd); 5064de189feSMasami Hiramatsu close(fd); 5074de189feSMasami Hiramatsu 508adf365f4SMasami Hiramatsu strlist__for_each(ent, rawlist) { 509af663d75SMasami Hiramatsu parse_trace_kprobe_event(ent->s, &pp); 510278498d4SMasami Hiramatsu /* Synthesize only event probe point */ 5117ef17aafSMasami Hiramatsu synthesize_perf_probe_point(&pp); 512278498d4SMasami Hiramatsu /* Show an event */ 513af663d75SMasami Hiramatsu show_perf_probe_event(pp.event, pp.probes[0], &pp); 5144de189feSMasami Hiramatsu clear_probe_point(&pp); 5154de189feSMasami Hiramatsu } 5164de189feSMasami Hiramatsu 5174de189feSMasami Hiramatsu strlist__delete(rawlist); 5184de189feSMasami Hiramatsu } 5194de189feSMasami Hiramatsu 520b498ce1fSMasami Hiramatsu /* Get current perf-probe event names */ 521fa28244dSMasami Hiramatsu static struct strlist *get_perf_event_names(int fd, bool include_group) 522b498ce1fSMasami Hiramatsu { 523fa28244dSMasami Hiramatsu char buf[128]; 524b498ce1fSMasami Hiramatsu struct strlist *sl, *rawlist; 525b498ce1fSMasami Hiramatsu struct str_node *ent; 526af663d75SMasami Hiramatsu struct probe_point pp; 527b498ce1fSMasami Hiramatsu 528af663d75SMasami Hiramatsu memset(&pp, 0, sizeof(pp)); 529b498ce1fSMasami Hiramatsu rawlist = get_trace_kprobe_event_rawlist(fd); 530b498ce1fSMasami Hiramatsu 531e1d2017bSMasami Hiramatsu sl = strlist__new(true, NULL); 532adf365f4SMasami Hiramatsu strlist__for_each(ent, rawlist) { 533af663d75SMasami Hiramatsu parse_trace_kprobe_event(ent->s, &pp); 534fa28244dSMasami Hiramatsu if (include_group) { 535af663d75SMasami Hiramatsu if (e_snprintf(buf, 128, "%s:%s", pp.group, 536af663d75SMasami Hiramatsu pp.event) < 0) 537fa28244dSMasami Hiramatsu die("Failed to copy group:event name."); 538fa28244dSMasami Hiramatsu strlist__add(sl, buf); 539fa28244dSMasami Hiramatsu } else 540af663d75SMasami Hiramatsu strlist__add(sl, pp.event); 541af663d75SMasami Hiramatsu clear_probe_point(&pp); 542b498ce1fSMasami Hiramatsu } 543b498ce1fSMasami Hiramatsu 544b498ce1fSMasami Hiramatsu strlist__delete(rawlist); 545b498ce1fSMasami Hiramatsu 546b498ce1fSMasami Hiramatsu return sl; 547b498ce1fSMasami Hiramatsu } 548b498ce1fSMasami Hiramatsu 549a9b495b0SMasami Hiramatsu static void write_trace_kprobe_event(int fd, const char *buf) 55050656eecSMasami Hiramatsu { 55150656eecSMasami Hiramatsu int ret; 55250656eecSMasami Hiramatsu 553fa28244dSMasami Hiramatsu pr_debug("Writing event: %s\n", buf); 55450656eecSMasami Hiramatsu ret = write(fd, buf, strlen(buf)); 55550656eecSMasami Hiramatsu if (ret <= 0) 556fa28244dSMasami Hiramatsu die("Failed to write event: %s", strerror(errno)); 55750656eecSMasami Hiramatsu } 55850656eecSMasami Hiramatsu 559b498ce1fSMasami Hiramatsu static void get_new_event_name(char *buf, size_t len, const char *base, 560d761b08bSMasami Hiramatsu struct strlist *namelist, bool allow_suffix) 561b498ce1fSMasami Hiramatsu { 562b498ce1fSMasami Hiramatsu int i, ret; 56317f88fcdSMasami Hiramatsu 56417f88fcdSMasami Hiramatsu /* Try no suffix */ 56517f88fcdSMasami Hiramatsu ret = e_snprintf(buf, len, "%s", base); 56617f88fcdSMasami Hiramatsu if (ret < 0) 56717f88fcdSMasami Hiramatsu die("snprintf() failed: %s", strerror(-ret)); 56817f88fcdSMasami Hiramatsu if (!strlist__has_entry(namelist, buf)) 56917f88fcdSMasami Hiramatsu return; 57017f88fcdSMasami Hiramatsu 571d761b08bSMasami Hiramatsu if (!allow_suffix) { 572d761b08bSMasami Hiramatsu pr_warning("Error: event \"%s\" already exists. " 573d761b08bSMasami Hiramatsu "(Use -f to force duplicates.)\n", base); 574d761b08bSMasami Hiramatsu die("Can't add new event."); 575d761b08bSMasami Hiramatsu } 576d761b08bSMasami Hiramatsu 57717f88fcdSMasami Hiramatsu /* Try to add suffix */ 57817f88fcdSMasami Hiramatsu for (i = 1; i < MAX_EVENT_INDEX; i++) { 579b498ce1fSMasami Hiramatsu ret = e_snprintf(buf, len, "%s_%d", base, i); 580b498ce1fSMasami Hiramatsu if (ret < 0) 581b498ce1fSMasami Hiramatsu die("snprintf() failed: %s", strerror(-ret)); 582b498ce1fSMasami Hiramatsu if (!strlist__has_entry(namelist, buf)) 583b498ce1fSMasami Hiramatsu break; 584b498ce1fSMasami Hiramatsu } 585b498ce1fSMasami Hiramatsu if (i == MAX_EVENT_INDEX) 586b498ce1fSMasami Hiramatsu die("Too many events are on the same function."); 587b498ce1fSMasami Hiramatsu } 588b498ce1fSMasami Hiramatsu 589d761b08bSMasami Hiramatsu void add_trace_kprobe_events(struct probe_point *probes, int nr_probes, 590d761b08bSMasami Hiramatsu bool force_add) 59150656eecSMasami Hiramatsu { 59250656eecSMasami Hiramatsu int i, j, fd; 59350656eecSMasami Hiramatsu struct probe_point *pp; 59450656eecSMasami Hiramatsu char buf[MAX_CMDLEN]; 595b498ce1fSMasami Hiramatsu char event[64]; 596b498ce1fSMasami Hiramatsu struct strlist *namelist; 597d761b08bSMasami Hiramatsu bool allow_suffix; 59850656eecSMasami Hiramatsu 599b498ce1fSMasami Hiramatsu fd = open_kprobe_events(O_RDWR, O_APPEND); 600b498ce1fSMasami Hiramatsu /* Get current event names */ 601fa28244dSMasami Hiramatsu namelist = get_perf_event_names(fd, false); 60250656eecSMasami Hiramatsu 60350656eecSMasami Hiramatsu for (j = 0; j < nr_probes; j++) { 60450656eecSMasami Hiramatsu pp = probes + j; 605af663d75SMasami Hiramatsu if (!pp->event) 606*31facc5fSMasami Hiramatsu pp->event = xstrdup(pp->function); 607af663d75SMasami Hiramatsu if (!pp->group) 608*31facc5fSMasami Hiramatsu pp->group = xstrdup(PERFPROBE_GROUP); 609d761b08bSMasami Hiramatsu /* If force_add is true, suffix search is allowed */ 610d761b08bSMasami Hiramatsu allow_suffix = force_add; 61150656eecSMasami Hiramatsu for (i = 0; i < pp->found; i++) { 612b498ce1fSMasami Hiramatsu /* Get an unused new event name */ 613d761b08bSMasami Hiramatsu get_new_event_name(event, 64, pp->event, namelist, 614d761b08bSMasami Hiramatsu allow_suffix); 615b498ce1fSMasami Hiramatsu snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s\n", 61650656eecSMasami Hiramatsu pp->retprobe ? 'r' : 'p', 617af663d75SMasami Hiramatsu pp->group, event, 61850656eecSMasami Hiramatsu pp->probes[i]); 61950656eecSMasami Hiramatsu write_trace_kprobe_event(fd, buf); 620a9b495b0SMasami Hiramatsu printf("Added new event:\n"); 621a9b495b0SMasami Hiramatsu /* Get the first parameter (probe-point) */ 622a9b495b0SMasami Hiramatsu sscanf(pp->probes[i], "%s", buf); 623af663d75SMasami Hiramatsu show_perf_probe_event(event, buf, pp); 624b498ce1fSMasami Hiramatsu /* Add added event name to namelist */ 625b498ce1fSMasami Hiramatsu strlist__add(namelist, event); 626d761b08bSMasami Hiramatsu /* 627d761b08bSMasami Hiramatsu * Probes after the first probe which comes from same 628d761b08bSMasami Hiramatsu * user input are always allowed to add suffix, because 629d761b08bSMasami Hiramatsu * there might be several addresses corresponding to 630d761b08bSMasami Hiramatsu * one code line. 631d761b08bSMasami Hiramatsu */ 632d761b08bSMasami Hiramatsu allow_suffix = true; 63350656eecSMasami Hiramatsu } 63450656eecSMasami Hiramatsu } 635a9b495b0SMasami Hiramatsu /* Show how to use the event. */ 636a9b495b0SMasami Hiramatsu printf("\nYou can now use it on all perf tools, such as:\n\n"); 637a9b495b0SMasami Hiramatsu printf("\tperf record -e %s:%s -a sleep 1\n\n", PERFPROBE_GROUP, event); 638a9b495b0SMasami Hiramatsu 639e1d2017bSMasami Hiramatsu strlist__delete(namelist); 64050656eecSMasami Hiramatsu close(fd); 64150656eecSMasami Hiramatsu } 642fa28244dSMasami Hiramatsu 643bbbb521bSMasami Hiramatsu static void __del_trace_kprobe_event(int fd, struct str_node *ent) 644bbbb521bSMasami Hiramatsu { 645bbbb521bSMasami Hiramatsu char *p; 646bbbb521bSMasami Hiramatsu char buf[128]; 647bbbb521bSMasami Hiramatsu 648bbbb521bSMasami Hiramatsu /* Convert from perf-probe event to trace-kprobe event */ 649bbbb521bSMasami Hiramatsu if (e_snprintf(buf, 128, "-:%s", ent->s) < 0) 650bbbb521bSMasami Hiramatsu die("Failed to copy event."); 651bbbb521bSMasami Hiramatsu p = strchr(buf + 2, ':'); 652bbbb521bSMasami Hiramatsu if (!p) 653bbbb521bSMasami Hiramatsu die("Internal error: %s should have ':' but not.", ent->s); 654bbbb521bSMasami Hiramatsu *p = '/'; 655bbbb521bSMasami Hiramatsu 656bbbb521bSMasami Hiramatsu write_trace_kprobe_event(fd, buf); 657bbbb521bSMasami Hiramatsu printf("Remove event: %s\n", ent->s); 658bbbb521bSMasami Hiramatsu } 659bbbb521bSMasami Hiramatsu 660fa28244dSMasami Hiramatsu static void del_trace_kprobe_event(int fd, const char *group, 661fa28244dSMasami Hiramatsu const char *event, struct strlist *namelist) 662fa28244dSMasami Hiramatsu { 663fa28244dSMasami Hiramatsu char buf[128]; 664bbbb521bSMasami Hiramatsu struct str_node *ent, *n; 665bbbb521bSMasami Hiramatsu int found = 0; 666fa28244dSMasami Hiramatsu 667fa28244dSMasami Hiramatsu if (e_snprintf(buf, 128, "%s:%s", group, event) < 0) 668fa28244dSMasami Hiramatsu die("Failed to copy event."); 669fa28244dSMasami Hiramatsu 670bbbb521bSMasami Hiramatsu if (strpbrk(buf, "*?")) { /* Glob-exp */ 671bbbb521bSMasami Hiramatsu strlist__for_each_safe(ent, n, namelist) 672bbbb521bSMasami Hiramatsu if (strglobmatch(ent->s, buf)) { 673bbbb521bSMasami Hiramatsu found++; 674bbbb521bSMasami Hiramatsu __del_trace_kprobe_event(fd, ent); 6753e340590SMasami Hiramatsu strlist__remove(namelist, ent); 676fa28244dSMasami Hiramatsu } 677bbbb521bSMasami Hiramatsu } else { 678bbbb521bSMasami Hiramatsu ent = strlist__find(namelist, buf); 679bbbb521bSMasami Hiramatsu if (ent) { 680bbbb521bSMasami Hiramatsu found++; 681bbbb521bSMasami Hiramatsu __del_trace_kprobe_event(fd, ent); 682bbbb521bSMasami Hiramatsu strlist__remove(namelist, ent); 683bbbb521bSMasami Hiramatsu } 684bbbb521bSMasami Hiramatsu } 685bbbb521bSMasami Hiramatsu if (found == 0) 686bbbb521bSMasami Hiramatsu pr_info("Info: event \"%s\" does not exist, could not remove it.\n", buf); 687bbbb521bSMasami Hiramatsu } 688fa28244dSMasami Hiramatsu 689fa28244dSMasami Hiramatsu void del_trace_kprobe_events(struct strlist *dellist) 690fa28244dSMasami Hiramatsu { 691fa28244dSMasami Hiramatsu int fd; 692fa28244dSMasami Hiramatsu const char *group, *event; 693fa28244dSMasami Hiramatsu char *p, *str; 694fa28244dSMasami Hiramatsu struct str_node *ent; 695fa28244dSMasami Hiramatsu struct strlist *namelist; 696fa28244dSMasami Hiramatsu 697fa28244dSMasami Hiramatsu fd = open_kprobe_events(O_RDWR, O_APPEND); 698fa28244dSMasami Hiramatsu /* Get current event names */ 699fa28244dSMasami Hiramatsu namelist = get_perf_event_names(fd, true); 700fa28244dSMasami Hiramatsu 701adf365f4SMasami Hiramatsu strlist__for_each(ent, dellist) { 702*31facc5fSMasami Hiramatsu str = xstrdup(ent->s); 703bbbb521bSMasami Hiramatsu pr_debug("Parsing: %s\n", str); 704fa28244dSMasami Hiramatsu p = strchr(str, ':'); 705fa28244dSMasami Hiramatsu if (p) { 706fa28244dSMasami Hiramatsu group = str; 707fa28244dSMasami Hiramatsu *p = '\0'; 708fa28244dSMasami Hiramatsu event = p + 1; 709fa28244dSMasami Hiramatsu } else { 710bbbb521bSMasami Hiramatsu group = "*"; 711fa28244dSMasami Hiramatsu event = str; 712fa28244dSMasami Hiramatsu } 713bbbb521bSMasami Hiramatsu pr_debug("Group: %s, Event: %s\n", group, event); 714fa28244dSMasami Hiramatsu del_trace_kprobe_event(fd, group, event, namelist); 715fa28244dSMasami Hiramatsu free(str); 716fa28244dSMasami Hiramatsu } 717fa28244dSMasami Hiramatsu strlist__delete(namelist); 718fa28244dSMasami Hiramatsu close(fd); 719fa28244dSMasami Hiramatsu } 720fa28244dSMasami Hiramatsu 721631c9defSMasami Hiramatsu #define LINEBUF_SIZE 256 7225c8d1cbbSMasami Hiramatsu #define NR_ADDITIONAL_LINES 2 723631c9defSMasami Hiramatsu 724631c9defSMasami Hiramatsu static void show_one_line(FILE *fp, unsigned int l, bool skip, bool show_num) 725631c9defSMasami Hiramatsu { 726631c9defSMasami Hiramatsu char buf[LINEBUF_SIZE]; 727631c9defSMasami Hiramatsu const char *color = PERF_COLOR_BLUE; 728631c9defSMasami Hiramatsu 729631c9defSMasami Hiramatsu if (fgets(buf, LINEBUF_SIZE, fp) == NULL) 730631c9defSMasami Hiramatsu goto error; 731631c9defSMasami Hiramatsu if (!skip) { 732631c9defSMasami Hiramatsu if (show_num) 733631c9defSMasami Hiramatsu fprintf(stdout, "%7u %s", l, buf); 734631c9defSMasami Hiramatsu else 735631c9defSMasami Hiramatsu color_fprintf(stdout, color, " %s", buf); 736631c9defSMasami Hiramatsu } 737631c9defSMasami Hiramatsu 738631c9defSMasami Hiramatsu while (strlen(buf) == LINEBUF_SIZE - 1 && 739631c9defSMasami Hiramatsu buf[LINEBUF_SIZE - 2] != '\n') { 740631c9defSMasami Hiramatsu if (fgets(buf, LINEBUF_SIZE, fp) == NULL) 741631c9defSMasami Hiramatsu goto error; 742631c9defSMasami Hiramatsu if (!skip) { 743631c9defSMasami Hiramatsu if (show_num) 744631c9defSMasami Hiramatsu fprintf(stdout, "%s", buf); 745631c9defSMasami Hiramatsu else 746631c9defSMasami Hiramatsu color_fprintf(stdout, color, "%s", buf); 747631c9defSMasami Hiramatsu } 748631c9defSMasami Hiramatsu } 749631c9defSMasami Hiramatsu return; 750631c9defSMasami Hiramatsu error: 751631c9defSMasami Hiramatsu if (feof(fp)) 752631c9defSMasami Hiramatsu die("Source file is shorter than expected."); 753631c9defSMasami Hiramatsu else 754631c9defSMasami Hiramatsu die("File read error: %s", strerror(errno)); 755631c9defSMasami Hiramatsu } 756631c9defSMasami Hiramatsu 757631c9defSMasami Hiramatsu void show_line_range(struct line_range *lr) 758631c9defSMasami Hiramatsu { 759631c9defSMasami Hiramatsu unsigned int l = 1; 760631c9defSMasami Hiramatsu struct line_node *ln; 761631c9defSMasami Hiramatsu FILE *fp; 762631c9defSMasami Hiramatsu 763631c9defSMasami Hiramatsu setup_pager(); 764631c9defSMasami Hiramatsu 765631c9defSMasami Hiramatsu if (lr->function) 766631c9defSMasami Hiramatsu fprintf(stdout, "<%s:%d>\n", lr->function, 767631c9defSMasami Hiramatsu lr->start - lr->offset); 768631c9defSMasami Hiramatsu else 769631c9defSMasami Hiramatsu fprintf(stdout, "<%s:%d>\n", lr->file, lr->start); 770631c9defSMasami Hiramatsu 771631c9defSMasami Hiramatsu fp = fopen(lr->path, "r"); 772631c9defSMasami Hiramatsu if (fp == NULL) 773631c9defSMasami Hiramatsu die("Failed to open %s: %s", lr->path, strerror(errno)); 774631c9defSMasami Hiramatsu /* Skip to starting line number */ 775631c9defSMasami Hiramatsu while (l < lr->start) 776631c9defSMasami Hiramatsu show_one_line(fp, l++, true, false); 777631c9defSMasami Hiramatsu 778631c9defSMasami Hiramatsu list_for_each_entry(ln, &lr->line_list, list) { 779631c9defSMasami Hiramatsu while (ln->line > l) 780631c9defSMasami Hiramatsu show_one_line(fp, (l++) - lr->offset, false, false); 781631c9defSMasami Hiramatsu show_one_line(fp, (l++) - lr->offset, false, true); 782631c9defSMasami Hiramatsu } 7835c8d1cbbSMasami Hiramatsu 7845c8d1cbbSMasami Hiramatsu if (lr->end == INT_MAX) 7855c8d1cbbSMasami Hiramatsu lr->end = l + NR_ADDITIONAL_LINES; 7865c8d1cbbSMasami Hiramatsu while (l < lr->end && !feof(fp)) 7875c8d1cbbSMasami Hiramatsu show_one_line(fp, (l++) - lr->offset, false, false); 7885c8d1cbbSMasami Hiramatsu 789631c9defSMasami Hiramatsu fclose(fp); 790631c9defSMasami Hiramatsu } 791