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 3650656eecSMasami Hiramatsu #include "event.h" 37e1c01d61SMasami Hiramatsu #include "string.h" 384de189feSMasami Hiramatsu #include "strlist.h" 3950656eecSMasami Hiramatsu #include "debug.h" 4072041334SMasami Hiramatsu #include "cache.h" 41631c9defSMasami Hiramatsu #include "color.h" 4250656eecSMasami Hiramatsu #include "parse-events.h" /* For debugfs_path */ 4350656eecSMasami Hiramatsu #include "probe-event.h" 4450656eecSMasami Hiramatsu 4550656eecSMasami Hiramatsu #define MAX_CMDLEN 256 4650656eecSMasami Hiramatsu #define MAX_PROBE_ARGS 128 4750656eecSMasami Hiramatsu #define PERFPROBE_GROUP "probe" 4850656eecSMasami Hiramatsu 4950656eecSMasami Hiramatsu #define semantic_error(msg ...) die("Semantic error :" msg) 5050656eecSMasami Hiramatsu 514de189feSMasami Hiramatsu /* If there is no space to write, returns -E2BIG. */ 524de189feSMasami Hiramatsu static int e_snprintf(char *str, size_t size, const char *format, ...) 5384988450SMasami Hiramatsu __attribute__((format(printf, 3, 4))); 5484988450SMasami Hiramatsu 5584988450SMasami Hiramatsu static int e_snprintf(char *str, size_t size, const char *format, ...) 564de189feSMasami Hiramatsu { 574de189feSMasami Hiramatsu int ret; 584de189feSMasami Hiramatsu va_list ap; 594de189feSMasami Hiramatsu va_start(ap, format); 604de189feSMasami Hiramatsu ret = vsnprintf(str, size, format, ap); 614de189feSMasami Hiramatsu va_end(ap); 624de189feSMasami Hiramatsu if (ret >= (int)size) 634de189feSMasami Hiramatsu ret = -E2BIG; 644de189feSMasami Hiramatsu return ret; 654de189feSMasami Hiramatsu } 664de189feSMasami Hiramatsu 67631c9defSMasami Hiramatsu void parse_line_range_desc(const char *arg, struct line_range *lr) 68631c9defSMasami Hiramatsu { 69631c9defSMasami Hiramatsu const char *ptr; 70631c9defSMasami Hiramatsu char *tmp; 71631c9defSMasami Hiramatsu /* 72631c9defSMasami Hiramatsu * <Syntax> 73631c9defSMasami Hiramatsu * SRC:SLN[+NUM|-ELN] 74631c9defSMasami Hiramatsu * FUNC[:SLN[+NUM|-ELN]] 75631c9defSMasami Hiramatsu */ 76631c9defSMasami Hiramatsu ptr = strchr(arg, ':'); 77631c9defSMasami Hiramatsu if (ptr) { 78631c9defSMasami Hiramatsu lr->start = (unsigned int)strtoul(ptr + 1, &tmp, 0); 79631c9defSMasami Hiramatsu if (*tmp == '+') 80631c9defSMasami Hiramatsu lr->end = lr->start + (unsigned int)strtoul(tmp + 1, 81631c9defSMasami Hiramatsu &tmp, 0); 82631c9defSMasami Hiramatsu else if (*tmp == '-') 83631c9defSMasami Hiramatsu lr->end = (unsigned int)strtoul(tmp + 1, &tmp, 0); 84631c9defSMasami Hiramatsu else 85631c9defSMasami Hiramatsu lr->end = 0; 86631c9defSMasami Hiramatsu pr_debug("Line range is %u to %u\n", lr->start, lr->end); 87631c9defSMasami Hiramatsu if (lr->end && lr->start > lr->end) 88631c9defSMasami Hiramatsu semantic_error("Start line must be smaller" 89631c9defSMasami Hiramatsu " than end line."); 90631c9defSMasami Hiramatsu if (*tmp != '\0') 91631c9defSMasami Hiramatsu semantic_error("Tailing with invalid character '%d'.", 92631c9defSMasami Hiramatsu *tmp); 93631c9defSMasami Hiramatsu tmp = strndup(arg, (ptr - arg)); 94631c9defSMasami Hiramatsu } else 95631c9defSMasami Hiramatsu tmp = strdup(arg); 96631c9defSMasami Hiramatsu 97631c9defSMasami Hiramatsu if (strchr(tmp, '.')) 98631c9defSMasami Hiramatsu lr->file = tmp; 99631c9defSMasami Hiramatsu else 100631c9defSMasami Hiramatsu lr->function = tmp; 101631c9defSMasami Hiramatsu } 102631c9defSMasami Hiramatsu 103b7702a21SMasami Hiramatsu /* Check the name is good for event/group */ 104b7702a21SMasami Hiramatsu static bool check_event_name(const char *name) 105b7702a21SMasami Hiramatsu { 106b7702a21SMasami Hiramatsu if (!isalpha(*name) && *name != '_') 107b7702a21SMasami Hiramatsu return false; 108b7702a21SMasami Hiramatsu while (*++name != '\0') { 109b7702a21SMasami Hiramatsu if (!isalpha(*name) && !isdigit(*name) && *name != '_') 110b7702a21SMasami Hiramatsu return false; 111b7702a21SMasami Hiramatsu } 112b7702a21SMasami Hiramatsu return true; 113b7702a21SMasami Hiramatsu } 114b7702a21SMasami Hiramatsu 11550656eecSMasami Hiramatsu /* Parse probepoint definition. */ 11650656eecSMasami Hiramatsu static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp) 11750656eecSMasami Hiramatsu { 11850656eecSMasami Hiramatsu char *ptr, *tmp; 11950656eecSMasami Hiramatsu char c, nc = 0; 12050656eecSMasami Hiramatsu /* 12150656eecSMasami Hiramatsu * <Syntax> 1222a9c8c36SMasami Hiramatsu * perf probe [EVENT=]SRC[:LN|;PTN] 1232a9c8c36SMasami Hiramatsu * perf probe [EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT] 124af663d75SMasami Hiramatsu * 125af663d75SMasami Hiramatsu * TODO:Group name support 12650656eecSMasami Hiramatsu */ 12750656eecSMasami Hiramatsu 1282a9c8c36SMasami Hiramatsu ptr = strpbrk(arg, ";=@+%"); 1292a9c8c36SMasami Hiramatsu if (ptr && *ptr == '=') { /* Event name */ 130af663d75SMasami Hiramatsu *ptr = '\0'; 131af663d75SMasami Hiramatsu tmp = ptr + 1; 132af663d75SMasami Hiramatsu ptr = strchr(arg, ':'); 133af663d75SMasami Hiramatsu if (ptr) /* Group name is not supported yet. */ 134af663d75SMasami Hiramatsu semantic_error("Group name is not supported yet."); 135b7702a21SMasami Hiramatsu if (!check_event_name(arg)) 136b7702a21SMasami Hiramatsu semantic_error("%s is bad for event name -it must " 137b7702a21SMasami Hiramatsu "follow C symbol-naming rule.", arg); 138af663d75SMasami Hiramatsu pp->event = strdup(arg); 139af663d75SMasami Hiramatsu arg = tmp; 140af663d75SMasami Hiramatsu } 141af663d75SMasami Hiramatsu 1422a9c8c36SMasami Hiramatsu ptr = strpbrk(arg, ";:+@%"); 14350656eecSMasami Hiramatsu if (ptr) { 14450656eecSMasami Hiramatsu nc = *ptr; 14550656eecSMasami Hiramatsu *ptr++ = '\0'; 14650656eecSMasami Hiramatsu } 14750656eecSMasami Hiramatsu 14850656eecSMasami Hiramatsu /* Check arg is function or file and copy it */ 14950656eecSMasami Hiramatsu if (strchr(arg, '.')) /* File */ 15050656eecSMasami Hiramatsu pp->file = strdup(arg); 15150656eecSMasami Hiramatsu else /* Function */ 15250656eecSMasami Hiramatsu pp->function = strdup(arg); 15350656eecSMasami Hiramatsu DIE_IF(pp->file == NULL && pp->function == NULL); 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 */ 1602a9c8c36SMasami Hiramatsu pp->lazy_line = strdup(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."); 18450656eecSMasami Hiramatsu pp->file = strdup(arg); 18550656eecSMasami Hiramatsu DIE_IF(pp->file == NULL); 18650656eecSMasami Hiramatsu break; 18750656eecSMasami Hiramatsu case '%': /* Probe places */ 18850656eecSMasami Hiramatsu if (strcmp(arg, "return") == 0) { 18950656eecSMasami Hiramatsu pp->retprobe = 1; 19050656eecSMasami Hiramatsu } else /* Others not supported yet */ 19150656eecSMasami Hiramatsu semantic_error("%%%s is not supported.", arg); 19250656eecSMasami Hiramatsu break; 19350656eecSMasami Hiramatsu default: 19450656eecSMasami Hiramatsu DIE_IF("Program has a bug."); 19550656eecSMasami Hiramatsu break; 19650656eecSMasami Hiramatsu } 19750656eecSMasami Hiramatsu } 19850656eecSMasami Hiramatsu 19950656eecSMasami Hiramatsu /* Exclusion check */ 2002a9c8c36SMasami Hiramatsu if (pp->lazy_line && pp->line) 2012a9c8c36SMasami Hiramatsu semantic_error("Lazy pattern can't be used with line number."); 2022a9c8c36SMasami Hiramatsu 2032a9c8c36SMasami Hiramatsu if (pp->lazy_line && pp->offset) 2042a9c8c36SMasami Hiramatsu semantic_error("Lazy pattern can't be used with offset."); 2052a9c8c36SMasami Hiramatsu 20650656eecSMasami Hiramatsu if (pp->line && pp->offset) 20750656eecSMasami Hiramatsu semantic_error("Offset can't be used with line number."); 20850656eecSMasami Hiramatsu 2092a9c8c36SMasami Hiramatsu if (!pp->line && !pp->lazy_line && pp->file && !pp->function) 2102a9c8c36SMasami Hiramatsu semantic_error("File always requires line number or " 2112a9c8c36SMasami Hiramatsu "lazy pattern."); 21250656eecSMasami Hiramatsu 21350656eecSMasami Hiramatsu if (pp->offset && !pp->function) 21450656eecSMasami Hiramatsu semantic_error("Offset requires an entry function."); 21550656eecSMasami Hiramatsu 21650656eecSMasami Hiramatsu if (pp->retprobe && !pp->function) 21750656eecSMasami Hiramatsu semantic_error("Return probe requires an entry function."); 21850656eecSMasami Hiramatsu 2192a9c8c36SMasami Hiramatsu if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) 2202a9c8c36SMasami Hiramatsu semantic_error("Offset/Line/Lazy pattern can't be used with " 2212a9c8c36SMasami Hiramatsu "return probe."); 22250656eecSMasami Hiramatsu 2232a9c8c36SMasami Hiramatsu pr_debug("symbol:%s file:%s line:%d offset:%d return:%d lazy:%s\n", 2242a9c8c36SMasami Hiramatsu pp->function, pp->file, pp->line, pp->offset, pp->retprobe, 2252a9c8c36SMasami Hiramatsu pp->lazy_line); 22650656eecSMasami Hiramatsu } 22750656eecSMasami Hiramatsu 22850656eecSMasami Hiramatsu /* Parse perf-probe event definition */ 229fac13fd5SMasami Hiramatsu void parse_perf_probe_event(const char *str, struct probe_point *pp, 230fac13fd5SMasami Hiramatsu bool *need_dwarf) 23150656eecSMasami Hiramatsu { 232e1c01d61SMasami Hiramatsu char **argv; 233fac13fd5SMasami Hiramatsu int argc, i; 234fac13fd5SMasami Hiramatsu 235fac13fd5SMasami Hiramatsu *need_dwarf = false; 23650656eecSMasami Hiramatsu 237e1c01d61SMasami Hiramatsu argv = argv_split(str, &argc); 238e1c01d61SMasami Hiramatsu if (!argv) 239e1c01d61SMasami Hiramatsu die("argv_split failed."); 240e1c01d61SMasami Hiramatsu if (argc > MAX_PROBE_ARGS + 1) 24150656eecSMasami Hiramatsu semantic_error("Too many arguments"); 24250656eecSMasami Hiramatsu 24350656eecSMasami Hiramatsu /* Parse probe point */ 24450656eecSMasami Hiramatsu parse_perf_probe_probepoint(argv[0], pp); 245*fc6ceea0SMasami Hiramatsu if (pp->file || pp->line || pp->lazy_line) 246fac13fd5SMasami Hiramatsu *need_dwarf = true; 24750656eecSMasami Hiramatsu 248e1c01d61SMasami Hiramatsu /* Copy arguments and ensure return probe has no C argument */ 24950656eecSMasami Hiramatsu pp->nr_args = argc - 1; 250e1c01d61SMasami Hiramatsu pp->args = zalloc(sizeof(char *) * pp->nr_args); 251e1c01d61SMasami Hiramatsu for (i = 0; i < pp->nr_args; i++) { 252e1c01d61SMasami Hiramatsu pp->args[i] = strdup(argv[i + 1]); 253e1c01d61SMasami Hiramatsu if (!pp->args[i]) 254e1c01d61SMasami Hiramatsu die("Failed to copy argument."); 25550656eecSMasami Hiramatsu if (is_c_varname(pp->args[i])) { 25650656eecSMasami Hiramatsu if (pp->retprobe) 25750656eecSMasami Hiramatsu semantic_error("You can't specify local" 25850656eecSMasami Hiramatsu " variable for kretprobe"); 259fac13fd5SMasami Hiramatsu *need_dwarf = true; 26050656eecSMasami Hiramatsu } 261e1c01d61SMasami Hiramatsu } 26250656eecSMasami Hiramatsu 263e1c01d61SMasami Hiramatsu argv_free(argv); 26450656eecSMasami Hiramatsu } 26550656eecSMasami Hiramatsu 2664de189feSMasami Hiramatsu /* Parse kprobe_events event into struct probe_point */ 267af663d75SMasami Hiramatsu void parse_trace_kprobe_event(const char *str, struct probe_point *pp) 2684de189feSMasami Hiramatsu { 2694de189feSMasami Hiramatsu char pr; 2704de189feSMasami Hiramatsu char *p; 2714de189feSMasami Hiramatsu int ret, i, argc; 2724de189feSMasami Hiramatsu char **argv; 2734de189feSMasami Hiramatsu 2744de189feSMasami Hiramatsu pr_debug("Parsing kprobe_events: %s\n", str); 2754de189feSMasami Hiramatsu argv = argv_split(str, &argc); 2764de189feSMasami Hiramatsu if (!argv) 2774de189feSMasami Hiramatsu die("argv_split failed."); 2784de189feSMasami Hiramatsu if (argc < 2) 2794de189feSMasami Hiramatsu semantic_error("Too less arguments."); 2804de189feSMasami Hiramatsu 2814de189feSMasami Hiramatsu /* Scan event and group name. */ 28293aaa45aSLiming Wang ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]", 283af663d75SMasami Hiramatsu &pr, (float *)(void *)&pp->group, 284af663d75SMasami Hiramatsu (float *)(void *)&pp->event); 2854de189feSMasami Hiramatsu if (ret != 3) 2864de189feSMasami Hiramatsu semantic_error("Failed to parse event name: %s", argv[0]); 287af663d75SMasami Hiramatsu pr_debug("Group:%s Event:%s probe:%c\n", pp->group, pp->event, pr); 2884de189feSMasami Hiramatsu 2894de189feSMasami Hiramatsu pp->retprobe = (pr == 'r'); 2904de189feSMasami Hiramatsu 2914de189feSMasami Hiramatsu /* Scan function name and offset */ 292af663d75SMasami Hiramatsu ret = sscanf(argv[1], "%a[^+]+%d", (float *)(void *)&pp->function, 293af663d75SMasami Hiramatsu &pp->offset); 2944de189feSMasami Hiramatsu if (ret == 1) 2954de189feSMasami Hiramatsu pp->offset = 0; 2964de189feSMasami Hiramatsu 2974de189feSMasami Hiramatsu /* kprobe_events doesn't have this information */ 2984de189feSMasami Hiramatsu pp->line = 0; 2994de189feSMasami Hiramatsu pp->file = NULL; 3004de189feSMasami Hiramatsu 3014de189feSMasami Hiramatsu pp->nr_args = argc - 2; 3024de189feSMasami Hiramatsu pp->args = zalloc(sizeof(char *) * pp->nr_args); 3034de189feSMasami Hiramatsu for (i = 0; i < pp->nr_args; i++) { 3044de189feSMasami Hiramatsu p = strchr(argv[i + 2], '='); 3054de189feSMasami Hiramatsu if (p) /* We don't need which register is assigned. */ 3064de189feSMasami Hiramatsu *p = '\0'; 3074de189feSMasami Hiramatsu pp->args[i] = strdup(argv[i + 2]); 3084de189feSMasami Hiramatsu if (!pp->args[i]) 3094de189feSMasami Hiramatsu die("Failed to copy argument."); 3104de189feSMasami Hiramatsu } 3114de189feSMasami Hiramatsu 3124de189feSMasami Hiramatsu argv_free(argv); 3134de189feSMasami Hiramatsu } 3144de189feSMasami Hiramatsu 3157ef17aafSMasami Hiramatsu /* Synthesize only probe point (not argument) */ 3167ef17aafSMasami Hiramatsu int synthesize_perf_probe_point(struct probe_point *pp) 31750656eecSMasami Hiramatsu { 31850656eecSMasami Hiramatsu char *buf; 3194de189feSMasami Hiramatsu char offs[64] = "", line[64] = ""; 3207ef17aafSMasami Hiramatsu int ret; 32150656eecSMasami Hiramatsu 32250656eecSMasami Hiramatsu pp->probes[0] = buf = zalloc(MAX_CMDLEN); 323388c3aabSMasami Hiramatsu pp->found = 1; 32450656eecSMasami Hiramatsu if (!buf) 32550656eecSMasami Hiramatsu die("Failed to allocate memory by zalloc."); 3264de189feSMasami Hiramatsu if (pp->offset) { 3274de189feSMasami Hiramatsu ret = e_snprintf(offs, 64, "+%d", pp->offset); 3284de189feSMasami Hiramatsu if (ret <= 0) 3294de189feSMasami Hiramatsu goto error; 3304de189feSMasami Hiramatsu } 3314de189feSMasami Hiramatsu if (pp->line) { 3324de189feSMasami Hiramatsu ret = e_snprintf(line, 64, ":%d", pp->line); 3334de189feSMasami Hiramatsu if (ret <= 0) 3344de189feSMasami Hiramatsu goto error; 3354de189feSMasami Hiramatsu } 3364de189feSMasami Hiramatsu 3374de189feSMasami Hiramatsu if (pp->function) 3384de189feSMasami Hiramatsu ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->function, 3394de189feSMasami Hiramatsu offs, pp->retprobe ? "%return" : "", line); 3404de189feSMasami Hiramatsu else 34184988450SMasami Hiramatsu ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", pp->file, line); 3427ef17aafSMasami Hiramatsu if (ret <= 0) { 3437ef17aafSMasami Hiramatsu error: 3447ef17aafSMasami Hiramatsu free(pp->probes[0]); 3457ef17aafSMasami Hiramatsu pp->probes[0] = NULL; 346388c3aabSMasami Hiramatsu pp->found = 0; 3477ef17aafSMasami Hiramatsu } 3487ef17aafSMasami Hiramatsu return ret; 3497ef17aafSMasami Hiramatsu } 35050656eecSMasami Hiramatsu 3517ef17aafSMasami Hiramatsu int synthesize_perf_probe_event(struct probe_point *pp) 3527ef17aafSMasami Hiramatsu { 3537ef17aafSMasami Hiramatsu char *buf; 3547ef17aafSMasami Hiramatsu int i, len, ret; 3557ef17aafSMasami Hiramatsu 3567ef17aafSMasami Hiramatsu len = synthesize_perf_probe_point(pp); 3577ef17aafSMasami Hiramatsu if (len < 0) 3587ef17aafSMasami Hiramatsu return 0; 3597ef17aafSMasami Hiramatsu 3607ef17aafSMasami Hiramatsu buf = pp->probes[0]; 36150656eecSMasami Hiramatsu for (i = 0; i < pp->nr_args; i++) { 3624de189feSMasami Hiramatsu ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s", 36350656eecSMasami Hiramatsu pp->args[i]); 3644de189feSMasami Hiramatsu if (ret <= 0) 36550656eecSMasami Hiramatsu goto error; 36650656eecSMasami Hiramatsu len += ret; 36750656eecSMasami Hiramatsu } 36850656eecSMasami Hiramatsu pp->found = 1; 36950656eecSMasami Hiramatsu 37050656eecSMasami Hiramatsu return pp->found; 37150656eecSMasami Hiramatsu error: 37250656eecSMasami Hiramatsu free(pp->probes[0]); 3737ef17aafSMasami Hiramatsu pp->probes[0] = NULL; 37450656eecSMasami Hiramatsu 37550656eecSMasami Hiramatsu return ret; 37650656eecSMasami Hiramatsu } 37750656eecSMasami Hiramatsu 3784de189feSMasami Hiramatsu int synthesize_trace_kprobe_event(struct probe_point *pp) 3794de189feSMasami Hiramatsu { 3804de189feSMasami Hiramatsu char *buf; 3814de189feSMasami Hiramatsu int i, len, ret; 3824de189feSMasami Hiramatsu 3834de189feSMasami Hiramatsu pp->probes[0] = buf = zalloc(MAX_CMDLEN); 3844de189feSMasami Hiramatsu if (!buf) 3854de189feSMasami Hiramatsu die("Failed to allocate memory by zalloc."); 3864de189feSMasami Hiramatsu ret = e_snprintf(buf, MAX_CMDLEN, "%s+%d", pp->function, pp->offset); 3874de189feSMasami Hiramatsu if (ret <= 0) 3884de189feSMasami Hiramatsu goto error; 3894de189feSMasami Hiramatsu len = ret; 3904de189feSMasami Hiramatsu 3914de189feSMasami Hiramatsu for (i = 0; i < pp->nr_args; i++) { 3924de189feSMasami Hiramatsu ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s", 3934de189feSMasami Hiramatsu pp->args[i]); 3944de189feSMasami Hiramatsu if (ret <= 0) 3954de189feSMasami Hiramatsu goto error; 3964de189feSMasami Hiramatsu len += ret; 3974de189feSMasami Hiramatsu } 3984de189feSMasami Hiramatsu pp->found = 1; 3994de189feSMasami Hiramatsu 4004de189feSMasami Hiramatsu return pp->found; 4014de189feSMasami Hiramatsu error: 4024de189feSMasami Hiramatsu free(pp->probes[0]); 4037ef17aafSMasami Hiramatsu pp->probes[0] = NULL; 4044de189feSMasami Hiramatsu 4054de189feSMasami Hiramatsu return ret; 4064de189feSMasami Hiramatsu } 4074de189feSMasami Hiramatsu 4084de189feSMasami Hiramatsu static int open_kprobe_events(int flags, int mode) 4094de189feSMasami Hiramatsu { 4104de189feSMasami Hiramatsu char buf[PATH_MAX]; 4114de189feSMasami Hiramatsu int ret; 4124de189feSMasami Hiramatsu 4134de189feSMasami Hiramatsu ret = e_snprintf(buf, PATH_MAX, "%s/../kprobe_events", debugfs_path); 4144de189feSMasami Hiramatsu if (ret < 0) 4154de189feSMasami Hiramatsu die("Failed to make kprobe_events path."); 4164de189feSMasami Hiramatsu 4174de189feSMasami Hiramatsu ret = open(buf, flags, mode); 4184de189feSMasami Hiramatsu if (ret < 0) { 4194de189feSMasami Hiramatsu if (errno == ENOENT) 4204de189feSMasami Hiramatsu die("kprobe_events file does not exist -" 42163bbd5e2SLiming Wang " please rebuild with CONFIG_KPROBE_EVENT."); 4224de189feSMasami Hiramatsu else 4234de189feSMasami Hiramatsu die("Could not open kprobe_events file: %s", 4244de189feSMasami Hiramatsu strerror(errno)); 4254de189feSMasami Hiramatsu } 4264de189feSMasami Hiramatsu return ret; 4274de189feSMasami Hiramatsu } 4284de189feSMasami Hiramatsu 4294de189feSMasami Hiramatsu /* Get raw string list of current kprobe_events */ 4304de189feSMasami Hiramatsu static struct strlist *get_trace_kprobe_event_rawlist(int fd) 4314de189feSMasami Hiramatsu { 4324de189feSMasami Hiramatsu int ret, idx; 4334de189feSMasami Hiramatsu FILE *fp; 4344de189feSMasami Hiramatsu char buf[MAX_CMDLEN]; 4354de189feSMasami Hiramatsu char *p; 4364de189feSMasami Hiramatsu struct strlist *sl; 4374de189feSMasami Hiramatsu 4384de189feSMasami Hiramatsu sl = strlist__new(true, NULL); 4394de189feSMasami Hiramatsu 4404de189feSMasami Hiramatsu fp = fdopen(dup(fd), "r"); 4414de189feSMasami Hiramatsu while (!feof(fp)) { 4424de189feSMasami Hiramatsu p = fgets(buf, MAX_CMDLEN, fp); 4434de189feSMasami Hiramatsu if (!p) 4444de189feSMasami Hiramatsu break; 4454de189feSMasami Hiramatsu 4464de189feSMasami Hiramatsu idx = strlen(p) - 1; 4474de189feSMasami Hiramatsu if (p[idx] == '\n') 4484de189feSMasami Hiramatsu p[idx] = '\0'; 4494de189feSMasami Hiramatsu ret = strlist__add(sl, buf); 4504de189feSMasami Hiramatsu if (ret < 0) 4514de189feSMasami Hiramatsu die("strlist__add failed: %s", strerror(-ret)); 4524de189feSMasami Hiramatsu } 4534de189feSMasami Hiramatsu fclose(fp); 4544de189feSMasami Hiramatsu 4554de189feSMasami Hiramatsu return sl; 4564de189feSMasami Hiramatsu } 4574de189feSMasami Hiramatsu 4584de189feSMasami Hiramatsu /* Free and zero clear probe_point */ 4594de189feSMasami Hiramatsu static void clear_probe_point(struct probe_point *pp) 4604de189feSMasami Hiramatsu { 4614de189feSMasami Hiramatsu int i; 4624de189feSMasami Hiramatsu 463af663d75SMasami Hiramatsu if (pp->event) 464af663d75SMasami Hiramatsu free(pp->event); 465af663d75SMasami Hiramatsu if (pp->group) 466af663d75SMasami Hiramatsu free(pp->group); 4674de189feSMasami Hiramatsu if (pp->function) 4684de189feSMasami Hiramatsu free(pp->function); 4694de189feSMasami Hiramatsu if (pp->file) 4704de189feSMasami Hiramatsu free(pp->file); 4712a9c8c36SMasami Hiramatsu if (pp->lazy_line) 4722a9c8c36SMasami Hiramatsu free(pp->lazy_line); 4734de189feSMasami Hiramatsu for (i = 0; i < pp->nr_args; i++) 4744de189feSMasami Hiramatsu free(pp->args[i]); 4754de189feSMasami Hiramatsu if (pp->args) 4764de189feSMasami Hiramatsu free(pp->args); 4774de189feSMasami Hiramatsu for (i = 0; i < pp->found; i++) 4784de189feSMasami Hiramatsu free(pp->probes[i]); 4795660ce34SJulia Lawall memset(pp, 0, sizeof(*pp)); 4804de189feSMasami Hiramatsu } 4814de189feSMasami Hiramatsu 482278498d4SMasami Hiramatsu /* Show an event */ 483af663d75SMasami Hiramatsu static void show_perf_probe_event(const char *event, const char *place, 484af663d75SMasami Hiramatsu struct probe_point *pp) 485278498d4SMasami Hiramatsu { 4867e990a51SMasami Hiramatsu int i, ret; 487278498d4SMasami Hiramatsu char buf[128]; 488278498d4SMasami Hiramatsu 489af663d75SMasami Hiramatsu ret = e_snprintf(buf, 128, "%s:%s", pp->group, event); 4907e990a51SMasami Hiramatsu if (ret < 0) 4917e990a51SMasami Hiramatsu die("Failed to copy event: %s", strerror(-ret)); 492278498d4SMasami Hiramatsu printf(" %-40s (on %s", buf, place); 493278498d4SMasami Hiramatsu 494278498d4SMasami Hiramatsu if (pp->nr_args > 0) { 495278498d4SMasami Hiramatsu printf(" with"); 496278498d4SMasami Hiramatsu for (i = 0; i < pp->nr_args; i++) 497278498d4SMasami Hiramatsu printf(" %s", pp->args[i]); 498278498d4SMasami Hiramatsu } 499278498d4SMasami Hiramatsu printf(")\n"); 500278498d4SMasami Hiramatsu } 501278498d4SMasami Hiramatsu 5024de189feSMasami Hiramatsu /* List up current perf-probe events */ 5034de189feSMasami Hiramatsu void show_perf_probe_events(void) 5044de189feSMasami Hiramatsu { 5057ef17aafSMasami Hiramatsu int fd; 5064de189feSMasami Hiramatsu struct probe_point pp; 5074de189feSMasami Hiramatsu struct strlist *rawlist; 5084de189feSMasami Hiramatsu struct str_node *ent; 5094de189feSMasami Hiramatsu 51072041334SMasami Hiramatsu setup_pager(); 511388c3aabSMasami Hiramatsu memset(&pp, 0, sizeof(pp)); 51272041334SMasami Hiramatsu 5134de189feSMasami Hiramatsu fd = open_kprobe_events(O_RDONLY, 0); 5144de189feSMasami Hiramatsu rawlist = get_trace_kprobe_event_rawlist(fd); 5154de189feSMasami Hiramatsu close(fd); 5164de189feSMasami Hiramatsu 517adf365f4SMasami Hiramatsu strlist__for_each(ent, rawlist) { 518af663d75SMasami Hiramatsu parse_trace_kprobe_event(ent->s, &pp); 519278498d4SMasami Hiramatsu /* Synthesize only event probe point */ 5207ef17aafSMasami Hiramatsu synthesize_perf_probe_point(&pp); 521278498d4SMasami Hiramatsu /* Show an event */ 522af663d75SMasami Hiramatsu show_perf_probe_event(pp.event, pp.probes[0], &pp); 5234de189feSMasami Hiramatsu clear_probe_point(&pp); 5244de189feSMasami Hiramatsu } 5254de189feSMasami Hiramatsu 5264de189feSMasami Hiramatsu strlist__delete(rawlist); 5274de189feSMasami Hiramatsu } 5284de189feSMasami Hiramatsu 529b498ce1fSMasami Hiramatsu /* Get current perf-probe event names */ 530fa28244dSMasami Hiramatsu static struct strlist *get_perf_event_names(int fd, bool include_group) 531b498ce1fSMasami Hiramatsu { 532fa28244dSMasami Hiramatsu char buf[128]; 533b498ce1fSMasami Hiramatsu struct strlist *sl, *rawlist; 534b498ce1fSMasami Hiramatsu struct str_node *ent; 535af663d75SMasami Hiramatsu struct probe_point pp; 536b498ce1fSMasami Hiramatsu 537af663d75SMasami Hiramatsu memset(&pp, 0, sizeof(pp)); 538b498ce1fSMasami Hiramatsu rawlist = get_trace_kprobe_event_rawlist(fd); 539b498ce1fSMasami Hiramatsu 540e1d2017bSMasami Hiramatsu sl = strlist__new(true, NULL); 541adf365f4SMasami Hiramatsu strlist__for_each(ent, rawlist) { 542af663d75SMasami Hiramatsu parse_trace_kprobe_event(ent->s, &pp); 543fa28244dSMasami Hiramatsu if (include_group) { 544af663d75SMasami Hiramatsu if (e_snprintf(buf, 128, "%s:%s", pp.group, 545af663d75SMasami Hiramatsu pp.event) < 0) 546fa28244dSMasami Hiramatsu die("Failed to copy group:event name."); 547fa28244dSMasami Hiramatsu strlist__add(sl, buf); 548fa28244dSMasami Hiramatsu } else 549af663d75SMasami Hiramatsu strlist__add(sl, pp.event); 550af663d75SMasami Hiramatsu clear_probe_point(&pp); 551b498ce1fSMasami Hiramatsu } 552b498ce1fSMasami Hiramatsu 553b498ce1fSMasami Hiramatsu strlist__delete(rawlist); 554b498ce1fSMasami Hiramatsu 555b498ce1fSMasami Hiramatsu return sl; 556b498ce1fSMasami Hiramatsu } 557b498ce1fSMasami Hiramatsu 558a9b495b0SMasami Hiramatsu static void write_trace_kprobe_event(int fd, const char *buf) 55950656eecSMasami Hiramatsu { 56050656eecSMasami Hiramatsu int ret; 56150656eecSMasami Hiramatsu 562fa28244dSMasami Hiramatsu pr_debug("Writing event: %s\n", buf); 56350656eecSMasami Hiramatsu ret = write(fd, buf, strlen(buf)); 56450656eecSMasami Hiramatsu if (ret <= 0) 565fa28244dSMasami Hiramatsu die("Failed to write event: %s", strerror(errno)); 56650656eecSMasami Hiramatsu } 56750656eecSMasami Hiramatsu 568b498ce1fSMasami Hiramatsu static void get_new_event_name(char *buf, size_t len, const char *base, 569d761b08bSMasami Hiramatsu struct strlist *namelist, bool allow_suffix) 570b498ce1fSMasami Hiramatsu { 571b498ce1fSMasami Hiramatsu int i, ret; 57217f88fcdSMasami Hiramatsu 57317f88fcdSMasami Hiramatsu /* Try no suffix */ 57417f88fcdSMasami Hiramatsu ret = e_snprintf(buf, len, "%s", base); 57517f88fcdSMasami Hiramatsu if (ret < 0) 57617f88fcdSMasami Hiramatsu die("snprintf() failed: %s", strerror(-ret)); 57717f88fcdSMasami Hiramatsu if (!strlist__has_entry(namelist, buf)) 57817f88fcdSMasami Hiramatsu return; 57917f88fcdSMasami Hiramatsu 580d761b08bSMasami Hiramatsu if (!allow_suffix) { 581d761b08bSMasami Hiramatsu pr_warning("Error: event \"%s\" already exists. " 582d761b08bSMasami Hiramatsu "(Use -f to force duplicates.)\n", base); 583d761b08bSMasami Hiramatsu die("Can't add new event."); 584d761b08bSMasami Hiramatsu } 585d761b08bSMasami Hiramatsu 58617f88fcdSMasami Hiramatsu /* Try to add suffix */ 58717f88fcdSMasami Hiramatsu for (i = 1; i < MAX_EVENT_INDEX; i++) { 588b498ce1fSMasami Hiramatsu ret = e_snprintf(buf, len, "%s_%d", base, i); 589b498ce1fSMasami Hiramatsu if (ret < 0) 590b498ce1fSMasami Hiramatsu die("snprintf() failed: %s", strerror(-ret)); 591b498ce1fSMasami Hiramatsu if (!strlist__has_entry(namelist, buf)) 592b498ce1fSMasami Hiramatsu break; 593b498ce1fSMasami Hiramatsu } 594b498ce1fSMasami Hiramatsu if (i == MAX_EVENT_INDEX) 595b498ce1fSMasami Hiramatsu die("Too many events are on the same function."); 596b498ce1fSMasami Hiramatsu } 597b498ce1fSMasami Hiramatsu 598d761b08bSMasami Hiramatsu void add_trace_kprobe_events(struct probe_point *probes, int nr_probes, 599d761b08bSMasami Hiramatsu bool force_add) 60050656eecSMasami Hiramatsu { 60150656eecSMasami Hiramatsu int i, j, fd; 60250656eecSMasami Hiramatsu struct probe_point *pp; 60350656eecSMasami Hiramatsu char buf[MAX_CMDLEN]; 604b498ce1fSMasami Hiramatsu char event[64]; 605b498ce1fSMasami Hiramatsu struct strlist *namelist; 606d761b08bSMasami Hiramatsu bool allow_suffix; 60750656eecSMasami Hiramatsu 608b498ce1fSMasami Hiramatsu fd = open_kprobe_events(O_RDWR, O_APPEND); 609b498ce1fSMasami Hiramatsu /* Get current event names */ 610fa28244dSMasami Hiramatsu namelist = get_perf_event_names(fd, false); 61150656eecSMasami Hiramatsu 61250656eecSMasami Hiramatsu for (j = 0; j < nr_probes; j++) { 61350656eecSMasami Hiramatsu pp = probes + j; 614af663d75SMasami Hiramatsu if (!pp->event) 615af663d75SMasami Hiramatsu pp->event = strdup(pp->function); 616af663d75SMasami Hiramatsu if (!pp->group) 617af663d75SMasami Hiramatsu pp->group = strdup(PERFPROBE_GROUP); 618af663d75SMasami Hiramatsu DIE_IF(!pp->event || !pp->group); 619d761b08bSMasami Hiramatsu /* If force_add is true, suffix search is allowed */ 620d761b08bSMasami Hiramatsu allow_suffix = force_add; 62150656eecSMasami Hiramatsu for (i = 0; i < pp->found; i++) { 622b498ce1fSMasami Hiramatsu /* Get an unused new event name */ 623d761b08bSMasami Hiramatsu get_new_event_name(event, 64, pp->event, namelist, 624d761b08bSMasami Hiramatsu allow_suffix); 625b498ce1fSMasami Hiramatsu snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s\n", 62650656eecSMasami Hiramatsu pp->retprobe ? 'r' : 'p', 627af663d75SMasami Hiramatsu pp->group, event, 62850656eecSMasami Hiramatsu pp->probes[i]); 62950656eecSMasami Hiramatsu write_trace_kprobe_event(fd, buf); 630a9b495b0SMasami Hiramatsu printf("Added new event:\n"); 631a9b495b0SMasami Hiramatsu /* Get the first parameter (probe-point) */ 632a9b495b0SMasami Hiramatsu sscanf(pp->probes[i], "%s", buf); 633af663d75SMasami Hiramatsu show_perf_probe_event(event, buf, pp); 634b498ce1fSMasami Hiramatsu /* Add added event name to namelist */ 635b498ce1fSMasami Hiramatsu strlist__add(namelist, event); 636d761b08bSMasami Hiramatsu /* 637d761b08bSMasami Hiramatsu * Probes after the first probe which comes from same 638d761b08bSMasami Hiramatsu * user input are always allowed to add suffix, because 639d761b08bSMasami Hiramatsu * there might be several addresses corresponding to 640d761b08bSMasami Hiramatsu * one code line. 641d761b08bSMasami Hiramatsu */ 642d761b08bSMasami Hiramatsu allow_suffix = true; 64350656eecSMasami Hiramatsu } 64450656eecSMasami Hiramatsu } 645a9b495b0SMasami Hiramatsu /* Show how to use the event. */ 646a9b495b0SMasami Hiramatsu printf("\nYou can now use it on all perf tools, such as:\n\n"); 647a9b495b0SMasami Hiramatsu printf("\tperf record -e %s:%s -a sleep 1\n\n", PERFPROBE_GROUP, event); 648a9b495b0SMasami Hiramatsu 649e1d2017bSMasami Hiramatsu strlist__delete(namelist); 65050656eecSMasami Hiramatsu close(fd); 65150656eecSMasami Hiramatsu } 652fa28244dSMasami Hiramatsu 653bbbb521bSMasami Hiramatsu static void __del_trace_kprobe_event(int fd, struct str_node *ent) 654bbbb521bSMasami Hiramatsu { 655bbbb521bSMasami Hiramatsu char *p; 656bbbb521bSMasami Hiramatsu char buf[128]; 657bbbb521bSMasami Hiramatsu 658bbbb521bSMasami Hiramatsu /* Convert from perf-probe event to trace-kprobe event */ 659bbbb521bSMasami Hiramatsu if (e_snprintf(buf, 128, "-:%s", ent->s) < 0) 660bbbb521bSMasami Hiramatsu die("Failed to copy event."); 661bbbb521bSMasami Hiramatsu p = strchr(buf + 2, ':'); 662bbbb521bSMasami Hiramatsu if (!p) 663bbbb521bSMasami Hiramatsu die("Internal error: %s should have ':' but not.", ent->s); 664bbbb521bSMasami Hiramatsu *p = '/'; 665bbbb521bSMasami Hiramatsu 666bbbb521bSMasami Hiramatsu write_trace_kprobe_event(fd, buf); 667bbbb521bSMasami Hiramatsu printf("Remove event: %s\n", ent->s); 668bbbb521bSMasami Hiramatsu } 669bbbb521bSMasami Hiramatsu 670fa28244dSMasami Hiramatsu static void del_trace_kprobe_event(int fd, const char *group, 671fa28244dSMasami Hiramatsu const char *event, struct strlist *namelist) 672fa28244dSMasami Hiramatsu { 673fa28244dSMasami Hiramatsu char buf[128]; 674bbbb521bSMasami Hiramatsu struct str_node *ent, *n; 675bbbb521bSMasami Hiramatsu int found = 0; 676fa28244dSMasami Hiramatsu 677fa28244dSMasami Hiramatsu if (e_snprintf(buf, 128, "%s:%s", group, event) < 0) 678fa28244dSMasami Hiramatsu die("Failed to copy event."); 679fa28244dSMasami Hiramatsu 680bbbb521bSMasami Hiramatsu if (strpbrk(buf, "*?")) { /* Glob-exp */ 681bbbb521bSMasami Hiramatsu strlist__for_each_safe(ent, n, namelist) 682bbbb521bSMasami Hiramatsu if (strglobmatch(ent->s, buf)) { 683bbbb521bSMasami Hiramatsu found++; 684bbbb521bSMasami Hiramatsu __del_trace_kprobe_event(fd, ent); 6853e340590SMasami Hiramatsu strlist__remove(namelist, ent); 686fa28244dSMasami Hiramatsu } 687bbbb521bSMasami Hiramatsu } else { 688bbbb521bSMasami Hiramatsu ent = strlist__find(namelist, buf); 689bbbb521bSMasami Hiramatsu if (ent) { 690bbbb521bSMasami Hiramatsu found++; 691bbbb521bSMasami Hiramatsu __del_trace_kprobe_event(fd, ent); 692bbbb521bSMasami Hiramatsu strlist__remove(namelist, ent); 693bbbb521bSMasami Hiramatsu } 694bbbb521bSMasami Hiramatsu } 695bbbb521bSMasami Hiramatsu if (found == 0) 696bbbb521bSMasami Hiramatsu pr_info("Info: event \"%s\" does not exist, could not remove it.\n", buf); 697bbbb521bSMasami Hiramatsu } 698fa28244dSMasami Hiramatsu 699fa28244dSMasami Hiramatsu void del_trace_kprobe_events(struct strlist *dellist) 700fa28244dSMasami Hiramatsu { 701fa28244dSMasami Hiramatsu int fd; 702fa28244dSMasami Hiramatsu const char *group, *event; 703fa28244dSMasami Hiramatsu char *p, *str; 704fa28244dSMasami Hiramatsu struct str_node *ent; 705fa28244dSMasami Hiramatsu struct strlist *namelist; 706fa28244dSMasami Hiramatsu 707fa28244dSMasami Hiramatsu fd = open_kprobe_events(O_RDWR, O_APPEND); 708fa28244dSMasami Hiramatsu /* Get current event names */ 709fa28244dSMasami Hiramatsu namelist = get_perf_event_names(fd, true); 710fa28244dSMasami Hiramatsu 711adf365f4SMasami Hiramatsu strlist__for_each(ent, dellist) { 712fa28244dSMasami Hiramatsu str = strdup(ent->s); 713fa28244dSMasami Hiramatsu if (!str) 714fa28244dSMasami Hiramatsu die("Failed to copy event."); 715bbbb521bSMasami Hiramatsu pr_debug("Parsing: %s\n", str); 716fa28244dSMasami Hiramatsu p = strchr(str, ':'); 717fa28244dSMasami Hiramatsu if (p) { 718fa28244dSMasami Hiramatsu group = str; 719fa28244dSMasami Hiramatsu *p = '\0'; 720fa28244dSMasami Hiramatsu event = p + 1; 721fa28244dSMasami Hiramatsu } else { 722bbbb521bSMasami Hiramatsu group = "*"; 723fa28244dSMasami Hiramatsu event = str; 724fa28244dSMasami Hiramatsu } 725bbbb521bSMasami Hiramatsu pr_debug("Group: %s, Event: %s\n", group, event); 726fa28244dSMasami Hiramatsu del_trace_kprobe_event(fd, group, event, namelist); 727fa28244dSMasami Hiramatsu free(str); 728fa28244dSMasami Hiramatsu } 729fa28244dSMasami Hiramatsu strlist__delete(namelist); 730fa28244dSMasami Hiramatsu close(fd); 731fa28244dSMasami Hiramatsu } 732fa28244dSMasami Hiramatsu 733631c9defSMasami Hiramatsu #define LINEBUF_SIZE 256 7345c8d1cbbSMasami Hiramatsu #define NR_ADDITIONAL_LINES 2 735631c9defSMasami Hiramatsu 736631c9defSMasami Hiramatsu static void show_one_line(FILE *fp, unsigned int l, bool skip, bool show_num) 737631c9defSMasami Hiramatsu { 738631c9defSMasami Hiramatsu char buf[LINEBUF_SIZE]; 739631c9defSMasami Hiramatsu const char *color = PERF_COLOR_BLUE; 740631c9defSMasami Hiramatsu 741631c9defSMasami Hiramatsu if (fgets(buf, LINEBUF_SIZE, fp) == NULL) 742631c9defSMasami Hiramatsu goto error; 743631c9defSMasami Hiramatsu if (!skip) { 744631c9defSMasami Hiramatsu if (show_num) 745631c9defSMasami Hiramatsu fprintf(stdout, "%7u %s", l, buf); 746631c9defSMasami Hiramatsu else 747631c9defSMasami Hiramatsu color_fprintf(stdout, color, " %s", buf); 748631c9defSMasami Hiramatsu } 749631c9defSMasami Hiramatsu 750631c9defSMasami Hiramatsu while (strlen(buf) == LINEBUF_SIZE - 1 && 751631c9defSMasami Hiramatsu buf[LINEBUF_SIZE - 2] != '\n') { 752631c9defSMasami Hiramatsu if (fgets(buf, LINEBUF_SIZE, fp) == NULL) 753631c9defSMasami Hiramatsu goto error; 754631c9defSMasami Hiramatsu if (!skip) { 755631c9defSMasami Hiramatsu if (show_num) 756631c9defSMasami Hiramatsu fprintf(stdout, "%s", buf); 757631c9defSMasami Hiramatsu else 758631c9defSMasami Hiramatsu color_fprintf(stdout, color, "%s", buf); 759631c9defSMasami Hiramatsu } 760631c9defSMasami Hiramatsu } 761631c9defSMasami Hiramatsu return; 762631c9defSMasami Hiramatsu error: 763631c9defSMasami Hiramatsu if (feof(fp)) 764631c9defSMasami Hiramatsu die("Source file is shorter than expected."); 765631c9defSMasami Hiramatsu else 766631c9defSMasami Hiramatsu die("File read error: %s", strerror(errno)); 767631c9defSMasami Hiramatsu } 768631c9defSMasami Hiramatsu 769631c9defSMasami Hiramatsu void show_line_range(struct line_range *lr) 770631c9defSMasami Hiramatsu { 771631c9defSMasami Hiramatsu unsigned int l = 1; 772631c9defSMasami Hiramatsu struct line_node *ln; 773631c9defSMasami Hiramatsu FILE *fp; 774631c9defSMasami Hiramatsu 775631c9defSMasami Hiramatsu setup_pager(); 776631c9defSMasami Hiramatsu 777631c9defSMasami Hiramatsu if (lr->function) 778631c9defSMasami Hiramatsu fprintf(stdout, "<%s:%d>\n", lr->function, 779631c9defSMasami Hiramatsu lr->start - lr->offset); 780631c9defSMasami Hiramatsu else 781631c9defSMasami Hiramatsu fprintf(stdout, "<%s:%d>\n", lr->file, lr->start); 782631c9defSMasami Hiramatsu 783631c9defSMasami Hiramatsu fp = fopen(lr->path, "r"); 784631c9defSMasami Hiramatsu if (fp == NULL) 785631c9defSMasami Hiramatsu die("Failed to open %s: %s", lr->path, strerror(errno)); 786631c9defSMasami Hiramatsu /* Skip to starting line number */ 787631c9defSMasami Hiramatsu while (l < lr->start) 788631c9defSMasami Hiramatsu show_one_line(fp, l++, true, false); 789631c9defSMasami Hiramatsu 790631c9defSMasami Hiramatsu list_for_each_entry(ln, &lr->line_list, list) { 791631c9defSMasami Hiramatsu while (ln->line > l) 792631c9defSMasami Hiramatsu show_one_line(fp, (l++) - lr->offset, false, false); 793631c9defSMasami Hiramatsu show_one_line(fp, (l++) - lr->offset, false, true); 794631c9defSMasami Hiramatsu } 7955c8d1cbbSMasami Hiramatsu 7965c8d1cbbSMasami Hiramatsu if (lr->end == INT_MAX) 7975c8d1cbbSMasami Hiramatsu lr->end = l + NR_ADDITIONAL_LINES; 7985c8d1cbbSMasami Hiramatsu while (l < lr->end && !feof(fp)) 7995c8d1cbbSMasami Hiramatsu show_one_line(fp, (l++) - lr->offset, false, false); 8005c8d1cbbSMasami Hiramatsu 801631c9defSMasami Hiramatsu fclose(fp); 802631c9defSMasami Hiramatsu } 803