1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2fd20e811SArnaldo Carvalho de Melo #include <inttypes.h> 3be8ecc57STony Garnock-Jones #include <signal.h> 4f048d548SNamhyung Kim #include <stdio.h> 5f048d548SNamhyung Kim #include <stdlib.h> 6f048d548SNamhyung Kim #include <string.h> 7be8ecc57STony Garnock-Jones #include <sys/types.h> 8f048d548SNamhyung Kim 9f048d548SNamhyung Kim #include <linux/kernel.h> 1013c230abSArnaldo Carvalho de Melo #include <linux/string.h> 117f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h> 12f048d548SNamhyung Kim 13b3801e79SIan Rogers #include <api/io.h> 14b3801e79SIan Rogers 1586c98cabSNamhyung Kim #include "util/dso.h" 16f048d548SNamhyung Kim #include "util/debug.h" 17a64489c5SJin Yao #include "util/callchain.h" 18b10c78c5SJin Yao #include "util/symbol_conf.h" 19632a5cabSArnaldo Carvalho de Melo #include "srcline.h" 207285cf33SNamhyung Kim #include "string2.h" 2185c116a6SAndi Kleen #include "symbol.h" 22be8ecc57STony Garnock-Jones #include "subcmd/run-command.h" 2385c116a6SAndi Kleen 24*701677b9SIan Rogers /* If addr2line doesn't return data for 1 second then timeout. */ 25*701677b9SIan Rogers int addr2line_timeout_ms = 1 * 1000; 26a9710ba0SAndi Kleen bool srcline_full_filename; 27a9710ba0SAndi Kleen 28922db21dSArnaldo Carvalho de Melo char *srcline__unknown = (char *)"??:0"; 29922db21dSArnaldo Carvalho de Melo 305580338dSJin Yao static const char *dso__name(struct dso *dso) 315580338dSJin Yao { 325580338dSJin Yao const char *dso_name; 335580338dSJin Yao 345580338dSJin Yao if (dso->symsrc_filename) 355580338dSJin Yao dso_name = dso->symsrc_filename; 365580338dSJin Yao else 375580338dSJin Yao dso_name = dso->long_name; 385580338dSJin Yao 395580338dSJin Yao if (dso_name[0] == '[') 405580338dSJin Yao return NULL; 415580338dSJin Yao 425580338dSJin Yao if (!strncmp(dso_name, "/tmp/perf-", 10)) 435580338dSJin Yao return NULL; 445580338dSJin Yao 455580338dSJin Yao return dso_name; 465580338dSJin Yao } 475580338dSJin Yao 482be8832fSMilian Wolff static int inline_list__append(struct symbol *symbol, char *srcline, 492be8832fSMilian Wolff struct inline_node *node) 50a64489c5SJin Yao { 51a64489c5SJin Yao struct inline_list *ilist; 52a64489c5SJin Yao 53a64489c5SJin Yao ilist = zalloc(sizeof(*ilist)); 54a64489c5SJin Yao if (ilist == NULL) 55a64489c5SJin Yao return -1; 56a64489c5SJin Yao 57fea0cf84SMilian Wolff ilist->symbol = symbol; 582be8832fSMilian Wolff ilist->srcline = srcline; 59a64489c5SJin Yao 6028071f51SMilian Wolff if (callchain_param.order == ORDER_CALLEE) 61a64489c5SJin Yao list_add_tail(&ilist->list, &node->val); 6228071f51SMilian Wolff else 6328071f51SMilian Wolff list_add(&ilist->list, &node->val); 64a64489c5SJin Yao 65a64489c5SJin Yao return 0; 66a64489c5SJin Yao } 67a64489c5SJin Yao 682be8832fSMilian Wolff /* basename version that takes a const input string */ 692be8832fSMilian Wolff static const char *gnu_basename(const char *path) 702be8832fSMilian Wolff { 712be8832fSMilian Wolff const char *base = strrchr(path, '/'); 722be8832fSMilian Wolff 732be8832fSMilian Wolff return base ? base + 1 : path; 742be8832fSMilian Wolff } 752be8832fSMilian Wolff 762be8832fSMilian Wolff static char *srcline_from_fileline(const char *file, unsigned int line) 772be8832fSMilian Wolff { 782be8832fSMilian Wolff char *srcline; 792be8832fSMilian Wolff 802be8832fSMilian Wolff if (!file) 812be8832fSMilian Wolff return NULL; 822be8832fSMilian Wolff 832be8832fSMilian Wolff if (!srcline_full_filename) 842be8832fSMilian Wolff file = gnu_basename(file); 852be8832fSMilian Wolff 862be8832fSMilian Wolff if (asprintf(&srcline, "%s:%u", file, line) < 0) 872be8832fSMilian Wolff return NULL; 882be8832fSMilian Wolff 892be8832fSMilian Wolff return srcline; 902be8832fSMilian Wolff } 912be8832fSMilian Wolff 927285cf33SNamhyung Kim static struct symbol *new_inline_sym(struct dso *dso, 937285cf33SNamhyung Kim struct symbol *base_sym, 947285cf33SNamhyung Kim const char *funcname) 957285cf33SNamhyung Kim { 967285cf33SNamhyung Kim struct symbol *inline_sym; 977285cf33SNamhyung Kim char *demangled = NULL; 987285cf33SNamhyung Kim 99d4046e8eSMilian Wolff if (!funcname) 100d4046e8eSMilian Wolff funcname = "??"; 101d4046e8eSMilian Wolff 1027285cf33SNamhyung Kim if (dso) { 1037285cf33SNamhyung Kim demangled = dso__demangle_sym(dso, 0, funcname); 1047285cf33SNamhyung Kim if (demangled) 1057285cf33SNamhyung Kim funcname = demangled; 1067285cf33SNamhyung Kim } 1077285cf33SNamhyung Kim 1087285cf33SNamhyung Kim if (base_sym && strcmp(funcname, base_sym->name) == 0) { 1097285cf33SNamhyung Kim /* reuse the real, existing symbol */ 1107285cf33SNamhyung Kim inline_sym = base_sym; 1117285cf33SNamhyung Kim /* ensure that we don't alias an inlined symbol, which could 1127285cf33SNamhyung Kim * lead to double frees in inline_node__delete 1137285cf33SNamhyung Kim */ 1147285cf33SNamhyung Kim assert(!base_sym->inlined); 1157285cf33SNamhyung Kim } else { 1167285cf33SNamhyung Kim /* create a fake symbol for the inline frame */ 1177285cf33SNamhyung Kim inline_sym = symbol__new(base_sym ? base_sym->start : 0, 1187346195eSHe Kuang base_sym ? (base_sym->end - base_sym->start) : 0, 1197285cf33SNamhyung Kim base_sym ? base_sym->binding : 0, 120af30bffaSArnaldo Carvalho de Melo base_sym ? base_sym->type : 0, 1217285cf33SNamhyung Kim funcname); 1227285cf33SNamhyung Kim if (inline_sym) 1237285cf33SNamhyung Kim inline_sym->inlined = 1; 1247285cf33SNamhyung Kim } 1257285cf33SNamhyung Kim 1267285cf33SNamhyung Kim free(demangled); 1277285cf33SNamhyung Kim 1287285cf33SNamhyung Kim return inline_sym; 1297285cf33SNamhyung Kim } 1307285cf33SNamhyung Kim 131be8ecc57STony Garnock-Jones #define MAX_INLINE_NEST 1024 132be8ecc57STony Garnock-Jones 1332f48fcd8SRoberto Vitillo #ifdef HAVE_LIBBFD_SUPPORT 1342f48fcd8SRoberto Vitillo 1352f48fcd8SRoberto Vitillo /* 1362f48fcd8SRoberto Vitillo * Implement addr2line using libbfd. 1372f48fcd8SRoberto Vitillo */ 1382f48fcd8SRoberto Vitillo #define PACKAGE "perf" 1392f48fcd8SRoberto Vitillo #include <bfd.h> 1402f48fcd8SRoberto Vitillo 1412f48fcd8SRoberto Vitillo struct a2l_data { 1422f48fcd8SRoberto Vitillo const char *input; 143ac931f87SWang Nan u64 addr; 1442f48fcd8SRoberto Vitillo 1452f48fcd8SRoberto Vitillo bool found; 1462f48fcd8SRoberto Vitillo const char *filename; 1472f48fcd8SRoberto Vitillo const char *funcname; 1482f48fcd8SRoberto Vitillo unsigned line; 1492f48fcd8SRoberto Vitillo 1502f48fcd8SRoberto Vitillo bfd *abfd; 1512f48fcd8SRoberto Vitillo asymbol **syms; 1522f48fcd8SRoberto Vitillo }; 1532f48fcd8SRoberto Vitillo 1542f48fcd8SRoberto Vitillo static int bfd_error(const char *string) 1552f48fcd8SRoberto Vitillo { 1562f48fcd8SRoberto Vitillo const char *errmsg; 1572f48fcd8SRoberto Vitillo 1582f48fcd8SRoberto Vitillo errmsg = bfd_errmsg(bfd_get_error()); 1592f48fcd8SRoberto Vitillo fflush(stdout); 1602f48fcd8SRoberto Vitillo 1612f48fcd8SRoberto Vitillo if (string) 1622f48fcd8SRoberto Vitillo pr_debug("%s: %s\n", string, errmsg); 1632f48fcd8SRoberto Vitillo else 1642f48fcd8SRoberto Vitillo pr_debug("%s\n", errmsg); 1652f48fcd8SRoberto Vitillo 1662f48fcd8SRoberto Vitillo return -1; 1672f48fcd8SRoberto Vitillo } 1682f48fcd8SRoberto Vitillo 1692f48fcd8SRoberto Vitillo static int slurp_symtab(bfd *abfd, struct a2l_data *a2l) 1702f48fcd8SRoberto Vitillo { 1712f48fcd8SRoberto Vitillo long storage; 1722f48fcd8SRoberto Vitillo long symcount; 1732f48fcd8SRoberto Vitillo asymbol **syms; 1742f48fcd8SRoberto Vitillo bfd_boolean dynamic = FALSE; 1752f48fcd8SRoberto Vitillo 1762f48fcd8SRoberto Vitillo if ((bfd_get_file_flags(abfd) & HAS_SYMS) == 0) 1772f48fcd8SRoberto Vitillo return bfd_error(bfd_get_filename(abfd)); 1782f48fcd8SRoberto Vitillo 1792f48fcd8SRoberto Vitillo storage = bfd_get_symtab_upper_bound(abfd); 1802f48fcd8SRoberto Vitillo if (storage == 0L) { 1812f48fcd8SRoberto Vitillo storage = bfd_get_dynamic_symtab_upper_bound(abfd); 1822f48fcd8SRoberto Vitillo dynamic = TRUE; 1832f48fcd8SRoberto Vitillo } 1842f48fcd8SRoberto Vitillo if (storage < 0L) 1852f48fcd8SRoberto Vitillo return bfd_error(bfd_get_filename(abfd)); 1862f48fcd8SRoberto Vitillo 1872f48fcd8SRoberto Vitillo syms = malloc(storage); 1882f48fcd8SRoberto Vitillo if (dynamic) 1892f48fcd8SRoberto Vitillo symcount = bfd_canonicalize_dynamic_symtab(abfd, syms); 1902f48fcd8SRoberto Vitillo else 1912f48fcd8SRoberto Vitillo symcount = bfd_canonicalize_symtab(abfd, syms); 1922f48fcd8SRoberto Vitillo 1932f48fcd8SRoberto Vitillo if (symcount < 0) { 1942f48fcd8SRoberto Vitillo free(syms); 1952f48fcd8SRoberto Vitillo return bfd_error(bfd_get_filename(abfd)); 1962f48fcd8SRoberto Vitillo } 1972f48fcd8SRoberto Vitillo 1982f48fcd8SRoberto Vitillo a2l->syms = syms; 1992f48fcd8SRoberto Vitillo return 0; 2002f48fcd8SRoberto Vitillo } 2012f48fcd8SRoberto Vitillo 2022f48fcd8SRoberto Vitillo static void find_address_in_section(bfd *abfd, asection *section, void *data) 2032f48fcd8SRoberto Vitillo { 2042f48fcd8SRoberto Vitillo bfd_vma pc, vma; 2052f48fcd8SRoberto Vitillo bfd_size_type size; 2062f48fcd8SRoberto Vitillo struct a2l_data *a2l = data; 2070ada120cSChangbin Du flagword flags; 2082f48fcd8SRoberto Vitillo 2092f48fcd8SRoberto Vitillo if (a2l->found) 2102f48fcd8SRoberto Vitillo return; 2112f48fcd8SRoberto Vitillo 2120ada120cSChangbin Du #ifdef bfd_get_section_flags 2130ada120cSChangbin Du flags = bfd_get_section_flags(abfd, section); 2140ada120cSChangbin Du #else 2150ada120cSChangbin Du flags = bfd_section_flags(section); 2160ada120cSChangbin Du #endif 2170ada120cSChangbin Du if ((flags & SEC_ALLOC) == 0) 2182f48fcd8SRoberto Vitillo return; 2192f48fcd8SRoberto Vitillo 2202f48fcd8SRoberto Vitillo pc = a2l->addr; 2210ada120cSChangbin Du #ifdef bfd_get_section_vma 2222f48fcd8SRoberto Vitillo vma = bfd_get_section_vma(abfd, section); 2230ada120cSChangbin Du #else 2240ada120cSChangbin Du vma = bfd_section_vma(section); 2250ada120cSChangbin Du #endif 2260ada120cSChangbin Du #ifdef bfd_get_section_size 2272f48fcd8SRoberto Vitillo size = bfd_get_section_size(section); 2280ada120cSChangbin Du #else 2290ada120cSChangbin Du size = bfd_section_size(section); 2300ada120cSChangbin Du #endif 2312f48fcd8SRoberto Vitillo 2322f48fcd8SRoberto Vitillo if (pc < vma || pc >= vma + size) 2332f48fcd8SRoberto Vitillo return; 2342f48fcd8SRoberto Vitillo 2352f48fcd8SRoberto Vitillo a2l->found = bfd_find_nearest_line(abfd, section, a2l->syms, pc - vma, 2362f48fcd8SRoberto Vitillo &a2l->filename, &a2l->funcname, 2372f48fcd8SRoberto Vitillo &a2l->line); 238d964b1cdSMilian Wolff 239d964b1cdSMilian Wolff if (a2l->filename && !strlen(a2l->filename)) 240d964b1cdSMilian Wolff a2l->filename = NULL; 2412f48fcd8SRoberto Vitillo } 2422f48fcd8SRoberto Vitillo 2432f48fcd8SRoberto Vitillo static struct a2l_data *addr2line_init(const char *path) 2442f48fcd8SRoberto Vitillo { 2452f48fcd8SRoberto Vitillo bfd *abfd; 2462f48fcd8SRoberto Vitillo struct a2l_data *a2l = NULL; 2472f48fcd8SRoberto Vitillo 2482f48fcd8SRoberto Vitillo abfd = bfd_openr(path, NULL); 2492f48fcd8SRoberto Vitillo if (abfd == NULL) 2502f48fcd8SRoberto Vitillo return NULL; 2512f48fcd8SRoberto Vitillo 2522f48fcd8SRoberto Vitillo if (!bfd_check_format(abfd, bfd_object)) 2532f48fcd8SRoberto Vitillo goto out; 2542f48fcd8SRoberto Vitillo 2552f48fcd8SRoberto Vitillo a2l = zalloc(sizeof(*a2l)); 2562f48fcd8SRoberto Vitillo if (a2l == NULL) 2572f48fcd8SRoberto Vitillo goto out; 2582f48fcd8SRoberto Vitillo 2592f48fcd8SRoberto Vitillo a2l->abfd = abfd; 2602f48fcd8SRoberto Vitillo a2l->input = strdup(path); 2612f48fcd8SRoberto Vitillo if (a2l->input == NULL) 2622f48fcd8SRoberto Vitillo goto out; 2632f48fcd8SRoberto Vitillo 2642f48fcd8SRoberto Vitillo if (slurp_symtab(abfd, a2l)) 2652f48fcd8SRoberto Vitillo goto out; 2662f48fcd8SRoberto Vitillo 2672f48fcd8SRoberto Vitillo return a2l; 2682f48fcd8SRoberto Vitillo 2692f48fcd8SRoberto Vitillo out: 2702f48fcd8SRoberto Vitillo if (a2l) { 2717d16c634SNamhyung Kim zfree((char **)&a2l->input); 2722f48fcd8SRoberto Vitillo free(a2l); 2732f48fcd8SRoberto Vitillo } 2742f48fcd8SRoberto Vitillo bfd_close(abfd); 2752f48fcd8SRoberto Vitillo return NULL; 2762f48fcd8SRoberto Vitillo } 2772f48fcd8SRoberto Vitillo 2782f48fcd8SRoberto Vitillo static void addr2line_cleanup(struct a2l_data *a2l) 2792f48fcd8SRoberto Vitillo { 2802f48fcd8SRoberto Vitillo if (a2l->abfd) 2812f48fcd8SRoberto Vitillo bfd_close(a2l->abfd); 2827d16c634SNamhyung Kim zfree((char **)&a2l->input); 28374cf249dSArnaldo Carvalho de Melo zfree(&a2l->syms); 2842f48fcd8SRoberto Vitillo free(a2l); 2852f48fcd8SRoberto Vitillo } 2862f48fcd8SRoberto Vitillo 2874d53b9d5SMilian Wolff static int inline_list__append_dso_a2l(struct dso *dso, 288fea0cf84SMilian Wolff struct inline_node *node, 289fea0cf84SMilian Wolff struct symbol *sym) 2904d53b9d5SMilian Wolff { 2914d53b9d5SMilian Wolff struct a2l_data *a2l = dso->a2l; 292fea0cf84SMilian Wolff struct symbol *inline_sym = new_inline_sym(dso, sym, a2l->funcname); 2932be8832fSMilian Wolff char *srcline = NULL; 2944d53b9d5SMilian Wolff 2952be8832fSMilian Wolff if (a2l->filename) 2962be8832fSMilian Wolff srcline = srcline_from_fileline(a2l->filename, a2l->line); 2972be8832fSMilian Wolff 2982be8832fSMilian Wolff return inline_list__append(inline_sym, srcline, node); 2994d53b9d5SMilian Wolff } 3004d53b9d5SMilian Wolff 301ac931f87SWang Nan static int addr2line(const char *dso_name, u64 addr, 3022f84b42bSAndi Kleen char **file, unsigned int *line, struct dso *dso, 303fea0cf84SMilian Wolff bool unwind_inlines, struct inline_node *node, 304fea0cf84SMilian Wolff struct symbol *sym) 3052f48fcd8SRoberto Vitillo { 3062f48fcd8SRoberto Vitillo int ret = 0; 307454ff00fSAdrian Hunter struct a2l_data *a2l = dso->a2l; 3082f48fcd8SRoberto Vitillo 309454ff00fSAdrian Hunter if (!a2l) { 310454ff00fSAdrian Hunter dso->a2l = addr2line_init(dso_name); 311454ff00fSAdrian Hunter a2l = dso->a2l; 312454ff00fSAdrian Hunter } 313454ff00fSAdrian Hunter 3142f48fcd8SRoberto Vitillo if (a2l == NULL) { 315b10c78c5SJin Yao if (!symbol_conf.disable_add2line_warn) 3162f48fcd8SRoberto Vitillo pr_warning("addr2line_init failed for %s\n", dso_name); 3172f48fcd8SRoberto Vitillo return 0; 3182f48fcd8SRoberto Vitillo } 3192f48fcd8SRoberto Vitillo 3202f48fcd8SRoberto Vitillo a2l->addr = addr; 321454ff00fSAdrian Hunter a2l->found = false; 322454ff00fSAdrian Hunter 3232f48fcd8SRoberto Vitillo bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l); 3242f48fcd8SRoberto Vitillo 325b21cc978SMilian Wolff if (!a2l->found) 326b21cc978SMilian Wolff return 0; 327b21cc978SMilian Wolff 328b21cc978SMilian Wolff if (unwind_inlines) { 3292f84b42bSAndi Kleen int cnt = 0; 3302f84b42bSAndi Kleen 331fea0cf84SMilian Wolff if (node && inline_list__append_dso_a2l(dso, node, sym)) 3324d53b9d5SMilian Wolff return 0; 3334d53b9d5SMilian Wolff 3342f84b42bSAndi Kleen while (bfd_find_inliner_info(a2l->abfd, &a2l->filename, 3352f84b42bSAndi Kleen &a2l->funcname, &a2l->line) && 336a64489c5SJin Yao cnt++ < MAX_INLINE_NEST) { 337a64489c5SJin Yao 338d964b1cdSMilian Wolff if (a2l->filename && !strlen(a2l->filename)) 339d964b1cdSMilian Wolff a2l->filename = NULL; 340d964b1cdSMilian Wolff 341a64489c5SJin Yao if (node != NULL) { 342fea0cf84SMilian Wolff if (inline_list__append_dso_a2l(dso, node, sym)) 343a64489c5SJin Yao return 0; 344b21cc978SMilian Wolff // found at least one inline frame 345b21cc978SMilian Wolff ret = 1; 346a64489c5SJin Yao } 347a64489c5SJin Yao } 3482f84b42bSAndi Kleen } 3492f84b42bSAndi Kleen 350b21cc978SMilian Wolff if (file) { 351b21cc978SMilian Wolff *file = a2l->filename ? strdup(a2l->filename) : NULL; 352b21cc978SMilian Wolff ret = *file ? 1 : 0; 3532f48fcd8SRoberto Vitillo } 3542f48fcd8SRoberto Vitillo 355b21cc978SMilian Wolff if (line) 356b21cc978SMilian Wolff *line = a2l->line; 357b21cc978SMilian Wolff 3582f48fcd8SRoberto Vitillo return ret; 3592f48fcd8SRoberto Vitillo } 3602f48fcd8SRoberto Vitillo 361454ff00fSAdrian Hunter void dso__free_a2l(struct dso *dso) 362454ff00fSAdrian Hunter { 363454ff00fSAdrian Hunter struct a2l_data *a2l = dso->a2l; 364454ff00fSAdrian Hunter 365454ff00fSAdrian Hunter if (!a2l) 366454ff00fSAdrian Hunter return; 367454ff00fSAdrian Hunter 368454ff00fSAdrian Hunter addr2line_cleanup(a2l); 369454ff00fSAdrian Hunter 370454ff00fSAdrian Hunter dso->a2l = NULL; 371454ff00fSAdrian Hunter } 372454ff00fSAdrian Hunter 3732f48fcd8SRoberto Vitillo #else /* HAVE_LIBBFD_SUPPORT */ 3742f48fcd8SRoberto Vitillo 3755580338dSJin Yao static int filename_split(char *filename, unsigned int *line_nr) 3765580338dSJin Yao { 3775580338dSJin Yao char *sep; 3785580338dSJin Yao 3795580338dSJin Yao sep = strchr(filename, '\n'); 3805580338dSJin Yao if (sep) 3815580338dSJin Yao *sep = '\0'; 3825580338dSJin Yao 3835580338dSJin Yao if (!strcmp(filename, "??:0")) 3845580338dSJin Yao return 0; 3855580338dSJin Yao 3865580338dSJin Yao sep = strchr(filename, ':'); 3875580338dSJin Yao if (sep) { 3885580338dSJin Yao *sep++ = '\0'; 3895580338dSJin Yao *line_nr = strtoul(sep, NULL, 0); 3905580338dSJin Yao return 1; 3915580338dSJin Yao } 3925580338dSJin Yao 3935580338dSJin Yao return 0; 3945580338dSJin Yao } 3955580338dSJin Yao 396b3801e79SIan Rogers static void addr2line_subprocess_cleanup(struct child_process *a2l) 397f048d548SNamhyung Kim { 398b3801e79SIan Rogers if (a2l->pid != -1) { 399b3801e79SIan Rogers kill(a2l->pid, SIGKILL); 400b3801e79SIan Rogers finish_command(a2l); /* ignore result, we don't care */ 401b3801e79SIan Rogers a2l->pid = -1; 402be8ecc57STony Garnock-Jones } 403be8ecc57STony Garnock-Jones 404be8ecc57STony Garnock-Jones free(a2l); 405be8ecc57STony Garnock-Jones } 406be8ecc57STony Garnock-Jones 407b3801e79SIan Rogers static struct child_process *addr2line_subprocess_init(const char *addr2line_path, 40857594454SIan Rogers const char *binary_path) 409be8ecc57STony Garnock-Jones { 41057594454SIan Rogers const char *argv[] = { 41157594454SIan Rogers addr2line_path ?: "addr2line", 41257594454SIan Rogers "-e", binary_path, 4138dc26b6fSIan Rogers "-a", "-i", "-f", NULL 41457594454SIan Rogers }; 415b3801e79SIan Rogers struct child_process *a2l = zalloc(sizeof(*a2l)); 416be8ecc57STony Garnock-Jones int start_command_status = 0; 417be8ecc57STony Garnock-Jones 418b3801e79SIan Rogers if (a2l == NULL) { 419b3801e79SIan Rogers pr_err("Failed to allocate memory for addr2line"); 420b3801e79SIan Rogers return NULL; 421b3801e79SIan Rogers } 422be8ecc57STony Garnock-Jones 423b3801e79SIan Rogers a2l->pid = -1; 424b3801e79SIan Rogers a2l->in = -1; 425b3801e79SIan Rogers a2l->out = -1; 426b3801e79SIan Rogers a2l->no_stderr = 1; 427be8ecc57STony Garnock-Jones 428b3801e79SIan Rogers a2l->argv = argv; 429b3801e79SIan Rogers start_command_status = start_command(a2l); 430b3801e79SIan Rogers a2l->argv = NULL; /* it's not used after start_command; avoid dangling pointers */ 431be8ecc57STony Garnock-Jones 432be8ecc57STony Garnock-Jones if (start_command_status != 0) { 43357594454SIan Rogers pr_warning("could not start addr2line (%s) for %s: start_command return code %d\n", 43457594454SIan Rogers addr2line_path, binary_path, start_command_status); 435be8ecc57STony Garnock-Jones addr2line_subprocess_cleanup(a2l); 436be8ecc57STony Garnock-Jones return NULL; 437be8ecc57STony Garnock-Jones } 438be8ecc57STony Garnock-Jones 439b3801e79SIan Rogers return a2l; 440b3801e79SIan Rogers } 441b3801e79SIan Rogers 4422c4b9280SIan Rogers enum a2l_style { 4432c4b9280SIan Rogers BROKEN, 4442c4b9280SIan Rogers GNU_BINUTILS, 4452c4b9280SIan Rogers LLVM, 4462c4b9280SIan Rogers }; 4472c4b9280SIan Rogers 448c7a0023aSIan Rogers static enum a2l_style addr2line_configure(struct child_process *a2l, const char *dso_name) 4492c4b9280SIan Rogers { 4502c4b9280SIan Rogers static bool cached; 4512c4b9280SIan Rogers static enum a2l_style style; 4522c4b9280SIan Rogers 4532c4b9280SIan Rogers if (!cached) { 4542c4b9280SIan Rogers char buf[128]; 4552c4b9280SIan Rogers struct io io; 4562c4b9280SIan Rogers int ch; 457c7a0023aSIan Rogers int lines; 4582c4b9280SIan Rogers 4592c4b9280SIan Rogers if (write(a2l->in, ",\n", 2) != 2) 4602c4b9280SIan Rogers return BROKEN; 4612c4b9280SIan Rogers 4622c4b9280SIan Rogers io__init(&io, a2l->out, buf, sizeof(buf)); 4632c4b9280SIan Rogers ch = io__get_char(&io); 4642c4b9280SIan Rogers if (ch == ',') { 4652c4b9280SIan Rogers style = LLVM; 4662c4b9280SIan Rogers cached = true; 467c7a0023aSIan Rogers lines = 1; 4688dc26b6fSIan Rogers } else if (ch == '0') { 4692c4b9280SIan Rogers style = GNU_BINUTILS; 4702c4b9280SIan Rogers cached = true; 4718dc26b6fSIan Rogers lines = 3; 4722c4b9280SIan Rogers } else { 473c7a0023aSIan Rogers if (!symbol_conf.disable_add2line_warn) { 474c7a0023aSIan Rogers char *output = NULL; 475c7a0023aSIan Rogers size_t output_len; 476c7a0023aSIan Rogers 477c7a0023aSIan Rogers io__getline(&io, &output, &output_len); 478c7a0023aSIan Rogers pr_warning("%s %s: addr2line configuration failed\n", 479c7a0023aSIan Rogers __func__, dso_name); 480c7a0023aSIan Rogers pr_warning("\t%c%s", ch, output); 4812c4b9280SIan Rogers } 482c7a0023aSIan Rogers return BROKEN; 483c7a0023aSIan Rogers } 484c7a0023aSIan Rogers while (lines) { 4852c4b9280SIan Rogers ch = io__get_char(&io); 486c7a0023aSIan Rogers if (ch <= 0) 487c7a0023aSIan Rogers break; 488c7a0023aSIan Rogers if (ch == '\n') 489c7a0023aSIan Rogers lines--; 4902c4b9280SIan Rogers } 49175a616c6SIan Rogers /* Ignore SIGPIPE in the event addr2line exits. */ 49275a616c6SIan Rogers signal(SIGPIPE, SIG_IGN); 4932c4b9280SIan Rogers } 4942c4b9280SIan Rogers return style; 4952c4b9280SIan Rogers } 4962c4b9280SIan Rogers 497b3801e79SIan Rogers static int read_addr2line_record(struct io *io, 4982c4b9280SIan Rogers enum a2l_style style, 499be8ecc57STony Garnock-Jones char **function, 500be8ecc57STony Garnock-Jones char **filename, 501be8ecc57STony Garnock-Jones unsigned int *line_nr) 502be8ecc57STony Garnock-Jones { 503be8ecc57STony Garnock-Jones /* 504be8ecc57STony Garnock-Jones * Returns: 505be8ecc57STony Garnock-Jones * -1 ==> error 506be8ecc57STony Garnock-Jones * 0 ==> sentinel (or other ill-formed) record read 507be8ecc57STony Garnock-Jones * 1 ==> a genuine record read 508be8ecc57STony Garnock-Jones */ 509be8ecc57STony Garnock-Jones char *line = NULL; 510be8ecc57STony Garnock-Jones size_t line_len = 0; 511be8ecc57STony Garnock-Jones unsigned int dummy_line_nr = 0; 512be8ecc57STony Garnock-Jones int ret = -1; 513be8ecc57STony Garnock-Jones 514be8ecc57STony Garnock-Jones if (function != NULL) 515be8ecc57STony Garnock-Jones zfree(function); 516be8ecc57STony Garnock-Jones 517be8ecc57STony Garnock-Jones if (filename != NULL) 518be8ecc57STony Garnock-Jones zfree(filename); 519be8ecc57STony Garnock-Jones 520be8ecc57STony Garnock-Jones if (line_nr != NULL) 521be8ecc57STony Garnock-Jones *line_nr = 0; 522be8ecc57STony Garnock-Jones 5238dc26b6fSIan Rogers /* 5248dc26b6fSIan Rogers * Read the first line. Without an error this will be either an address 5258dc26b6fSIan Rogers * like 0x1234 or for llvm-addr2line the sentinal ',' character. 5268dc26b6fSIan Rogers */ 527b3801e79SIan Rogers if (io__getline(io, &line, &line_len) < 0 || !line_len) 528be8ecc57STony Garnock-Jones goto error; 5292c4b9280SIan Rogers 5308dc26b6fSIan Rogers if (style == LLVM) { 5318dc26b6fSIan Rogers if (line_len == 2 && line[0] == ',') { 5322c4b9280SIan Rogers zfree(&line); 5332c4b9280SIan Rogers return 0; 5342c4b9280SIan Rogers } 5358dc26b6fSIan Rogers } else { 5368dc26b6fSIan Rogers int zero_count = 0, non_zero_count = 0; 5378dc26b6fSIan Rogers 5388dc26b6fSIan Rogers /* The address should always start 0x. */ 5398dc26b6fSIan Rogers if (line_len < 2 || line[0] != '0' || line[1] != 'x') 5408dc26b6fSIan Rogers goto error; 5418dc26b6fSIan Rogers 5428dc26b6fSIan Rogers for (size_t i = 2; i < line_len; i++) { 5438dc26b6fSIan Rogers if (line[i] == '0') 5448dc26b6fSIan Rogers zero_count++; 5458dc26b6fSIan Rogers else if (line[i] != '\n') 5468dc26b6fSIan Rogers non_zero_count++; 5478dc26b6fSIan Rogers } 5488dc26b6fSIan Rogers if (!non_zero_count) { 5498dc26b6fSIan Rogers int ch; 5508dc26b6fSIan Rogers 5518dc26b6fSIan Rogers if (!zero_count) { 5528dc26b6fSIan Rogers /* Line was erroneous just '0x'. */ 5538dc26b6fSIan Rogers goto error; 5548dc26b6fSIan Rogers } 5558dc26b6fSIan Rogers /* 5568dc26b6fSIan Rogers * Line was 0x0..0, the sentinel for binutils. Remove 5578dc26b6fSIan Rogers * the function and filename lines. 5588dc26b6fSIan Rogers */ 5598dc26b6fSIan Rogers zfree(&line); 5608dc26b6fSIan Rogers do { 5618dc26b6fSIan Rogers ch = io__get_char(io); 5628dc26b6fSIan Rogers } while (ch > 0 && ch != '\n'); 5638dc26b6fSIan Rogers do { 5648dc26b6fSIan Rogers ch = io__get_char(io); 5658dc26b6fSIan Rogers } while (ch > 0 && ch != '\n'); 5668dc26b6fSIan Rogers return 0; 5678dc26b6fSIan Rogers } 5688dc26b6fSIan Rogers } 5698dc26b6fSIan Rogers 5708dc26b6fSIan Rogers /* Read the second function name line. */ 5718dc26b6fSIan Rogers if (io__getline(io, &line, &line_len) < 0 || !line_len) 5728dc26b6fSIan Rogers goto error; 5732c4b9280SIan Rogers 574be8ecc57STony Garnock-Jones if (function != NULL) 575be8ecc57STony Garnock-Jones *function = strdup(strim(line)); 576be8ecc57STony Garnock-Jones 577be8ecc57STony Garnock-Jones zfree(&line); 578be8ecc57STony Garnock-Jones line_len = 0; 579be8ecc57STony Garnock-Jones 5808dc26b6fSIan Rogers /* Read the third filename and line number line. */ 581b3801e79SIan Rogers if (io__getline(io, &line, &line_len) < 0 || !line_len) 582be8ecc57STony Garnock-Jones goto error; 583be8ecc57STony Garnock-Jones 5842c4b9280SIan Rogers if (filename_split(line, line_nr == NULL ? &dummy_line_nr : line_nr) == 0 && 5852c4b9280SIan Rogers style == GNU_BINUTILS) { 586be8ecc57STony Garnock-Jones ret = 0; 587be8ecc57STony Garnock-Jones goto error; 588be8ecc57STony Garnock-Jones } 589be8ecc57STony Garnock-Jones 590be8ecc57STony Garnock-Jones if (filename != NULL) 591be8ecc57STony Garnock-Jones *filename = strdup(line); 592be8ecc57STony Garnock-Jones 593be8ecc57STony Garnock-Jones zfree(&line); 594be8ecc57STony Garnock-Jones line_len = 0; 595be8ecc57STony Garnock-Jones 596be8ecc57STony Garnock-Jones return 1; 597be8ecc57STony Garnock-Jones 598be8ecc57STony Garnock-Jones error: 599be8ecc57STony Garnock-Jones free(line); 600be8ecc57STony Garnock-Jones if (function != NULL) 601be8ecc57STony Garnock-Jones zfree(function); 602be8ecc57STony Garnock-Jones if (filename != NULL) 603be8ecc57STony Garnock-Jones zfree(filename); 604f048d548SNamhyung Kim return ret; 605f048d548SNamhyung Kim } 606454ff00fSAdrian Hunter 607be8ecc57STony Garnock-Jones static int inline_list__append_record(struct dso *dso, 608be8ecc57STony Garnock-Jones struct inline_node *node, 609be8ecc57STony Garnock-Jones struct symbol *sym, 610be8ecc57STony Garnock-Jones const char *function, 611be8ecc57STony Garnock-Jones const char *filename, 612be8ecc57STony Garnock-Jones unsigned int line_nr) 613454ff00fSAdrian Hunter { 614be8ecc57STony Garnock-Jones struct symbol *inline_sym = new_inline_sym(dso, sym, function); 615be8ecc57STony Garnock-Jones 616be8ecc57STony Garnock-Jones return inline_list__append(inline_sym, srcline_from_fileline(filename, line_nr), node); 617454ff00fSAdrian Hunter } 618454ff00fSAdrian Hunter 619be8ecc57STony Garnock-Jones static int addr2line(const char *dso_name, u64 addr, 620be8ecc57STony Garnock-Jones char **file, unsigned int *line_nr, 621be8ecc57STony Garnock-Jones struct dso *dso, 622be8ecc57STony Garnock-Jones bool unwind_inlines, 623be8ecc57STony Garnock-Jones struct inline_node *node, 624be8ecc57STony Garnock-Jones struct symbol *sym __maybe_unused) 625be8ecc57STony Garnock-Jones { 626b3801e79SIan Rogers struct child_process *a2l = dso->a2l; 627be8ecc57STony Garnock-Jones char *record_function = NULL; 628be8ecc57STony Garnock-Jones char *record_filename = NULL; 629be8ecc57STony Garnock-Jones unsigned int record_line_nr = 0; 630be8ecc57STony Garnock-Jones int record_status = -1; 631be8ecc57STony Garnock-Jones int ret = 0; 632be8ecc57STony Garnock-Jones size_t inline_count = 0; 633b3801e79SIan Rogers int len; 634b3801e79SIan Rogers char buf[128]; 635b3801e79SIan Rogers ssize_t written; 636*701677b9SIan Rogers struct io io = { .eof = false }; 6372c4b9280SIan Rogers enum a2l_style a2l_style; 638be8ecc57STony Garnock-Jones 639be8ecc57STony Garnock-Jones if (!a2l) { 6403b27222dSNamhyung Kim if (!filename__has_section(dso_name, ".debug_line")) 6413b27222dSNamhyung Kim goto out; 6423b27222dSNamhyung Kim 64357594454SIan Rogers dso->a2l = addr2line_subprocess_init(symbol_conf.addr2line_path, 64457594454SIan Rogers dso_name); 645be8ecc57STony Garnock-Jones a2l = dso->a2l; 646be8ecc57STony Garnock-Jones } 647be8ecc57STony Garnock-Jones 648be8ecc57STony Garnock-Jones if (a2l == NULL) { 649be8ecc57STony Garnock-Jones if (!symbol_conf.disable_add2line_warn) 650be8ecc57STony Garnock-Jones pr_warning("%s %s: addr2line_subprocess_init failed\n", __func__, dso_name); 651be8ecc57STony Garnock-Jones goto out; 652be8ecc57STony Garnock-Jones } 653c7a0023aSIan Rogers a2l_style = addr2line_configure(a2l, dso_name); 654c7a0023aSIan Rogers if (a2l_style == BROKEN) 6552c4b9280SIan Rogers goto out; 656be8ecc57STony Garnock-Jones 657be8ecc57STony Garnock-Jones /* 658be8ecc57STony Garnock-Jones * Send our request and then *deliberately* send something that can't be interpreted as 659be8ecc57STony Garnock-Jones * a valid address to ask addr2line about (namely, ","). This causes addr2line to first 660be8ecc57STony Garnock-Jones * write out the answer to our request, in an unbounded/unknown number of records, and 6612c4b9280SIan Rogers * then to write out the lines "??" and "??:0", for GNU binutils, or "," for 6622c4b9280SIan Rogers * llvm-addr2line, so that we can detect when it has finished giving us anything 6632c4b9280SIan Rogers * useful. With GNU binutils, we have to be careful about the first record, though, 6642c4b9280SIan Rogers * because it may be genuinely unknown, in which case we'll get two sets of "??"/"??:0" 6652c4b9280SIan Rogers * lines. 666be8ecc57STony Garnock-Jones */ 667b3801e79SIan Rogers len = snprintf(buf, sizeof(buf), "%016"PRIx64"\n,\n", addr); 668b3801e79SIan Rogers written = len > 0 ? write(a2l->in, buf, len) : -1; 669b3801e79SIan Rogers if (written != len) { 670d5e33ce0SNamhyung Kim if (!symbol_conf.disable_add2line_warn) 671be8ecc57STony Garnock-Jones pr_warning("%s %s: could not send request\n", __func__, dso_name); 672be8ecc57STony Garnock-Jones goto out; 673be8ecc57STony Garnock-Jones } 674b3801e79SIan Rogers io__init(&io, a2l->out, buf, sizeof(buf)); 675*701677b9SIan Rogers io.timeout_ms = addr2line_timeout_ms; 6762c4b9280SIan Rogers switch (read_addr2line_record(&io, a2l_style, 6772c4b9280SIan Rogers &record_function, &record_filename, &record_line_nr)) { 678be8ecc57STony Garnock-Jones case -1: 679d5e33ce0SNamhyung Kim if (!symbol_conf.disable_add2line_warn) 680be8ecc57STony Garnock-Jones pr_warning("%s %s: could not read first record\n", __func__, dso_name); 681be8ecc57STony Garnock-Jones goto out; 682be8ecc57STony Garnock-Jones case 0: 683be8ecc57STony Garnock-Jones /* 6848dc26b6fSIan Rogers * The first record was invalid, so return failure, but first 6858dc26b6fSIan Rogers * read another record, since we sent a sentinel ',' for the 6868dc26b6fSIan Rogers * sake of detected the last inlined function. 687be8ecc57STony Garnock-Jones */ 6882c4b9280SIan Rogers switch (read_addr2line_record(&io, a2l_style, NULL, NULL, NULL)) { 689be8ecc57STony Garnock-Jones case -1: 690d5e33ce0SNamhyung Kim if (!symbol_conf.disable_add2line_warn) 691d5e33ce0SNamhyung Kim pr_warning("%s %s: could not read delimiter record\n", 692d5e33ce0SNamhyung Kim __func__, dso_name); 693be8ecc57STony Garnock-Jones break; 694be8ecc57STony Garnock-Jones case 0: 695be8ecc57STony Garnock-Jones /* As expected. */ 696be8ecc57STony Garnock-Jones break; 697be8ecc57STony Garnock-Jones default: 698d5e33ce0SNamhyung Kim if (!symbol_conf.disable_add2line_warn) 699be8ecc57STony Garnock-Jones pr_warning("%s %s: unexpected record instead of sentinel", 700be8ecc57STony Garnock-Jones __func__, dso_name); 701be8ecc57STony Garnock-Jones break; 702be8ecc57STony Garnock-Jones } 703be8ecc57STony Garnock-Jones goto out; 704be8ecc57STony Garnock-Jones default: 705be8ecc57STony Garnock-Jones break; 706be8ecc57STony Garnock-Jones } 707be8ecc57STony Garnock-Jones 708be8ecc57STony Garnock-Jones if (file) { 709be8ecc57STony Garnock-Jones *file = strdup(record_filename); 710be8ecc57STony Garnock-Jones ret = 1; 711be8ecc57STony Garnock-Jones } 712be8ecc57STony Garnock-Jones if (line_nr) 713be8ecc57STony Garnock-Jones *line_nr = record_line_nr; 714be8ecc57STony Garnock-Jones 715be8ecc57STony Garnock-Jones if (unwind_inlines) { 716be8ecc57STony Garnock-Jones if (node && inline_list__append_record(dso, node, sym, 717be8ecc57STony Garnock-Jones record_function, 718be8ecc57STony Garnock-Jones record_filename, 719be8ecc57STony Garnock-Jones record_line_nr)) { 720be8ecc57STony Garnock-Jones ret = 0; 721be8ecc57STony Garnock-Jones goto out; 722be8ecc57STony Garnock-Jones } 723be8ecc57STony Garnock-Jones } 724be8ecc57STony Garnock-Jones 725be8ecc57STony Garnock-Jones /* We have to read the records even if we don't care about the inline info. */ 726b3801e79SIan Rogers while ((record_status = read_addr2line_record(&io, 7272c4b9280SIan Rogers a2l_style, 728be8ecc57STony Garnock-Jones &record_function, 729be8ecc57STony Garnock-Jones &record_filename, 730be8ecc57STony Garnock-Jones &record_line_nr)) == 1) { 731be8ecc57STony Garnock-Jones if (unwind_inlines && node && inline_count++ < MAX_INLINE_NEST) { 732be8ecc57STony Garnock-Jones if (inline_list__append_record(dso, node, sym, 733be8ecc57STony Garnock-Jones record_function, 734be8ecc57STony Garnock-Jones record_filename, 735be8ecc57STony Garnock-Jones record_line_nr)) { 736be8ecc57STony Garnock-Jones ret = 0; 737be8ecc57STony Garnock-Jones goto out; 738be8ecc57STony Garnock-Jones } 739be8ecc57STony Garnock-Jones ret = 1; /* found at least one inline frame */ 740be8ecc57STony Garnock-Jones } 741be8ecc57STony Garnock-Jones } 742be8ecc57STony Garnock-Jones 743be8ecc57STony Garnock-Jones out: 744be8ecc57STony Garnock-Jones free(record_function); 745be8ecc57STony Garnock-Jones free(record_filename); 746*701677b9SIan Rogers if (io.eof) { 747*701677b9SIan Rogers dso->a2l = NULL; 748*701677b9SIan Rogers addr2line_subprocess_cleanup(a2l); 749*701677b9SIan Rogers } 750be8ecc57STony Garnock-Jones return ret; 751be8ecc57STony Garnock-Jones } 752be8ecc57STony Garnock-Jones 753be8ecc57STony Garnock-Jones void dso__free_a2l(struct dso *dso) 754be8ecc57STony Garnock-Jones { 755b3801e79SIan Rogers struct child_process *a2l = dso->a2l; 756be8ecc57STony Garnock-Jones 757be8ecc57STony Garnock-Jones if (!a2l) 758be8ecc57STony Garnock-Jones return; 759be8ecc57STony Garnock-Jones 760be8ecc57STony Garnock-Jones addr2line_subprocess_cleanup(a2l); 761be8ecc57STony Garnock-Jones 762be8ecc57STony Garnock-Jones dso->a2l = NULL; 763be8ecc57STony Garnock-Jones } 764be8ecc57STony Garnock-Jones 765be8ecc57STony Garnock-Jones #endif /* HAVE_LIBBFD_SUPPORT */ 766be8ecc57STony Garnock-Jones 767a64489c5SJin Yao static struct inline_node *addr2inlines(const char *dso_name, u64 addr, 768be8ecc57STony Garnock-Jones struct dso *dso, struct symbol *sym) 769a64489c5SJin Yao { 770a64489c5SJin Yao struct inline_node *node; 771a64489c5SJin Yao 772a64489c5SJin Yao node = zalloc(sizeof(*node)); 773a64489c5SJin Yao if (node == NULL) { 774a64489c5SJin Yao perror("not enough memory for the inline node"); 775be8ecc57STony Garnock-Jones return NULL; 776a64489c5SJin Yao } 777a64489c5SJin Yao 778a64489c5SJin Yao INIT_LIST_HEAD(&node->val); 779a64489c5SJin Yao node->addr = addr; 780a64489c5SJin Yao 781be8ecc57STony Garnock-Jones addr2line(dso_name, addr, NULL, NULL, dso, true, node, sym); 782a64489c5SJin Yao return node; 783a64489c5SJin Yao } 784a64489c5SJin Yao 785906049c8SAdrian Hunter /* 786906049c8SAdrian Hunter * Number of addr2line failures (without success) before disabling it for that 787906049c8SAdrian Hunter * dso. 788906049c8SAdrian Hunter */ 789906049c8SAdrian Hunter #define A2L_FAIL_LIMIT 123 790906049c8SAdrian Hunter 7912f84b42bSAndi Kleen char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym, 792935f5a9dSJin Yao bool show_sym, bool show_addr, bool unwind_inlines, 793935f5a9dSJin Yao u64 ip) 794f048d548SNamhyung Kim { 795a949fffbSDavid Ahern char *file = NULL; 796a949fffbSDavid Ahern unsigned line = 0; 7972cc9d0efSNamhyung Kim char *srcline; 798bf4414aeSArnaldo Carvalho de Melo const char *dso_name; 799f048d548SNamhyung Kim 8002cc9d0efSNamhyung Kim if (!dso->has_srcline) 80123f0981bSAndi Kleen goto out; 8022cc9d0efSNamhyung Kim 8035580338dSJin Yao dso_name = dso__name(dso); 8045580338dSJin Yao if (dso_name == NULL) 80558d91a00SNamhyung Kim goto out; 80658d91a00SNamhyung Kim 807fea0cf84SMilian Wolff if (!addr2line(dso_name, addr, &file, &line, dso, 808fea0cf84SMilian Wolff unwind_inlines, NULL, sym)) 80958d91a00SNamhyung Kim goto out; 810f048d548SNamhyung Kim 8112be8832fSMilian Wolff srcline = srcline_from_fileline(file, line); 812906049c8SAdrian Hunter free(file); 8132be8832fSMilian Wolff 8142be8832fSMilian Wolff if (!srcline) 815906049c8SAdrian Hunter goto out; 816906049c8SAdrian Hunter 817906049c8SAdrian Hunter dso->a2l_fails = 0; 818f048d548SNamhyung Kim 819f048d548SNamhyung Kim return srcline; 8202cc9d0efSNamhyung Kim 8212cc9d0efSNamhyung Kim out: 822906049c8SAdrian Hunter if (dso->a2l_fails && ++dso->a2l_fails > A2L_FAIL_LIMIT) { 8232cc9d0efSNamhyung Kim dso->has_srcline = 0; 824454ff00fSAdrian Hunter dso__free_a2l(dso); 825906049c8SAdrian Hunter } 8265dfa210eSMilian Wolff 8275dfa210eSMilian Wolff if (!show_addr) 8285dfa210eSMilian Wolff return (show_sym && sym) ? 829ea335ef3SNamhyung Kim strndup(sym->name, sym->namelen) : SRCLINE_UNKNOWN; 8305dfa210eSMilian Wolff 83185c116a6SAndi Kleen if (sym) { 832ac931f87SWang Nan if (asprintf(&srcline, "%s+%" PRIu64, show_sym ? sym->name : "", 833935f5a9dSJin Yao ip - sym->start) < 0) 83485c116a6SAndi Kleen return SRCLINE_UNKNOWN; 835ac931f87SWang Nan } else if (asprintf(&srcline, "%s[%" PRIx64 "]", dso->short_name, addr) < 0) 8362cc9d0efSNamhyung Kim return SRCLINE_UNKNOWN; 83723f0981bSAndi Kleen return srcline; 838f048d548SNamhyung Kim } 839f048d548SNamhyung Kim 840dd2e18e9SAndi Kleen /* Returns filename and fills in line number in line */ 841dd2e18e9SAndi Kleen char *get_srcline_split(struct dso *dso, u64 addr, unsigned *line) 842dd2e18e9SAndi Kleen { 843dd2e18e9SAndi Kleen char *file = NULL; 844dd2e18e9SAndi Kleen const char *dso_name; 845dd2e18e9SAndi Kleen 846dd2e18e9SAndi Kleen if (!dso->has_srcline) 847dd2e18e9SAndi Kleen goto out; 848dd2e18e9SAndi Kleen 849dd2e18e9SAndi Kleen dso_name = dso__name(dso); 850dd2e18e9SAndi Kleen if (dso_name == NULL) 851dd2e18e9SAndi Kleen goto out; 852dd2e18e9SAndi Kleen 853dd2e18e9SAndi Kleen if (!addr2line(dso_name, addr, &file, line, dso, true, NULL, NULL)) 854dd2e18e9SAndi Kleen goto out; 855dd2e18e9SAndi Kleen 856dd2e18e9SAndi Kleen dso->a2l_fails = 0; 857dd2e18e9SAndi Kleen return file; 858dd2e18e9SAndi Kleen 859dd2e18e9SAndi Kleen out: 860dd2e18e9SAndi Kleen if (dso->a2l_fails && ++dso->a2l_fails > A2L_FAIL_LIMIT) { 861dd2e18e9SAndi Kleen dso->has_srcline = 0; 862dd2e18e9SAndi Kleen dso__free_a2l(dso); 863dd2e18e9SAndi Kleen } 864dd2e18e9SAndi Kleen 865dd2e18e9SAndi Kleen return NULL; 866dd2e18e9SAndi Kleen } 867dd2e18e9SAndi Kleen 868625db36eSIan Rogers void zfree_srcline(char **srcline) 869f048d548SNamhyung Kim { 870625db36eSIan Rogers if (*srcline == NULL) 871625db36eSIan Rogers return; 872625db36eSIan Rogers 873922db21dSArnaldo Carvalho de Melo if (*srcline != SRCLINE_UNKNOWN) 874625db36eSIan Rogers free(*srcline); 875625db36eSIan Rogers 876625db36eSIan Rogers *srcline = NULL; 877f048d548SNamhyung Kim } 8782f84b42bSAndi Kleen 8792f84b42bSAndi Kleen char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym, 880935f5a9dSJin Yao bool show_sym, bool show_addr, u64 ip) 8812f84b42bSAndi Kleen { 882935f5a9dSJin Yao return __get_srcline(dso, addr, sym, show_sym, show_addr, false, ip); 8832f84b42bSAndi Kleen } 884a64489c5SJin Yao 88521ac9d54SMilian Wolff struct srcline_node { 88621ac9d54SMilian Wolff u64 addr; 88721ac9d54SMilian Wolff char *srcline; 88821ac9d54SMilian Wolff struct rb_node rb_node; 88921ac9d54SMilian Wolff }; 89021ac9d54SMilian Wolff 89155ecd631SDavidlohr Bueso void srcline__tree_insert(struct rb_root_cached *tree, u64 addr, char *srcline) 89221ac9d54SMilian Wolff { 89355ecd631SDavidlohr Bueso struct rb_node **p = &tree->rb_root.rb_node; 89421ac9d54SMilian Wolff struct rb_node *parent = NULL; 89521ac9d54SMilian Wolff struct srcline_node *i, *node; 89655ecd631SDavidlohr Bueso bool leftmost = true; 89721ac9d54SMilian Wolff 89821ac9d54SMilian Wolff node = zalloc(sizeof(struct srcline_node)); 89921ac9d54SMilian Wolff if (!node) { 90021ac9d54SMilian Wolff perror("not enough memory for the srcline node"); 90121ac9d54SMilian Wolff return; 90221ac9d54SMilian Wolff } 90321ac9d54SMilian Wolff 90421ac9d54SMilian Wolff node->addr = addr; 90521ac9d54SMilian Wolff node->srcline = srcline; 90621ac9d54SMilian Wolff 90721ac9d54SMilian Wolff while (*p != NULL) { 90821ac9d54SMilian Wolff parent = *p; 90921ac9d54SMilian Wolff i = rb_entry(parent, struct srcline_node, rb_node); 91021ac9d54SMilian Wolff if (addr < i->addr) 91121ac9d54SMilian Wolff p = &(*p)->rb_left; 91255ecd631SDavidlohr Bueso else { 91321ac9d54SMilian Wolff p = &(*p)->rb_right; 91455ecd631SDavidlohr Bueso leftmost = false; 91555ecd631SDavidlohr Bueso } 91621ac9d54SMilian Wolff } 91721ac9d54SMilian Wolff rb_link_node(&node->rb_node, parent, p); 91855ecd631SDavidlohr Bueso rb_insert_color_cached(&node->rb_node, tree, leftmost); 91921ac9d54SMilian Wolff } 92021ac9d54SMilian Wolff 92155ecd631SDavidlohr Bueso char *srcline__tree_find(struct rb_root_cached *tree, u64 addr) 92221ac9d54SMilian Wolff { 92355ecd631SDavidlohr Bueso struct rb_node *n = tree->rb_root.rb_node; 92421ac9d54SMilian Wolff 92521ac9d54SMilian Wolff while (n) { 92621ac9d54SMilian Wolff struct srcline_node *i = rb_entry(n, struct srcline_node, 92721ac9d54SMilian Wolff rb_node); 92821ac9d54SMilian Wolff 92921ac9d54SMilian Wolff if (addr < i->addr) 93021ac9d54SMilian Wolff n = n->rb_left; 93121ac9d54SMilian Wolff else if (addr > i->addr) 93221ac9d54SMilian Wolff n = n->rb_right; 93321ac9d54SMilian Wolff else 93421ac9d54SMilian Wolff return i->srcline; 93521ac9d54SMilian Wolff } 93621ac9d54SMilian Wolff 93721ac9d54SMilian Wolff return NULL; 93821ac9d54SMilian Wolff } 93921ac9d54SMilian Wolff 94055ecd631SDavidlohr Bueso void srcline__tree_delete(struct rb_root_cached *tree) 94121ac9d54SMilian Wolff { 94221ac9d54SMilian Wolff struct srcline_node *pos; 94355ecd631SDavidlohr Bueso struct rb_node *next = rb_first_cached(tree); 94421ac9d54SMilian Wolff 94521ac9d54SMilian Wolff while (next) { 94621ac9d54SMilian Wolff pos = rb_entry(next, struct srcline_node, rb_node); 94721ac9d54SMilian Wolff next = rb_next(&pos->rb_node); 94855ecd631SDavidlohr Bueso rb_erase_cached(&pos->rb_node, tree); 949625db36eSIan Rogers zfree_srcline(&pos->srcline); 95021ac9d54SMilian Wolff zfree(&pos); 95121ac9d54SMilian Wolff } 95221ac9d54SMilian Wolff } 95321ac9d54SMilian Wolff 954fea0cf84SMilian Wolff struct inline_node *dso__parse_addr_inlines(struct dso *dso, u64 addr, 955fea0cf84SMilian Wolff struct symbol *sym) 956a64489c5SJin Yao { 957a64489c5SJin Yao const char *dso_name; 958a64489c5SJin Yao 959a64489c5SJin Yao dso_name = dso__name(dso); 960a64489c5SJin Yao if (dso_name == NULL) 961a64489c5SJin Yao return NULL; 962a64489c5SJin Yao 963fea0cf84SMilian Wolff return addr2inlines(dso_name, addr, dso, sym); 964a64489c5SJin Yao } 965a64489c5SJin Yao 966a64489c5SJin Yao void inline_node__delete(struct inline_node *node) 967a64489c5SJin Yao { 968a64489c5SJin Yao struct inline_list *ilist, *tmp; 969a64489c5SJin Yao 970a64489c5SJin Yao list_for_each_entry_safe(ilist, tmp, &node->val, list) { 971a64489c5SJin Yao list_del_init(&ilist->list); 972625db36eSIan Rogers zfree_srcline(&ilist->srcline); 973fea0cf84SMilian Wolff /* only the inlined symbols are owned by the list */ 974fea0cf84SMilian Wolff if (ilist->symbol && ilist->symbol->inlined) 975fea0cf84SMilian Wolff symbol__delete(ilist->symbol); 976a64489c5SJin Yao free(ilist); 977a64489c5SJin Yao } 978a64489c5SJin Yao 979a64489c5SJin Yao free(node); 980a64489c5SJin Yao } 98111ea2515SMilian Wolff 98255ecd631SDavidlohr Bueso void inlines__tree_insert(struct rb_root_cached *tree, 98355ecd631SDavidlohr Bueso struct inline_node *inlines) 98411ea2515SMilian Wolff { 98555ecd631SDavidlohr Bueso struct rb_node **p = &tree->rb_root.rb_node; 98611ea2515SMilian Wolff struct rb_node *parent = NULL; 98711ea2515SMilian Wolff const u64 addr = inlines->addr; 98811ea2515SMilian Wolff struct inline_node *i; 98955ecd631SDavidlohr Bueso bool leftmost = true; 99011ea2515SMilian Wolff 99111ea2515SMilian Wolff while (*p != NULL) { 99211ea2515SMilian Wolff parent = *p; 99311ea2515SMilian Wolff i = rb_entry(parent, struct inline_node, rb_node); 99411ea2515SMilian Wolff if (addr < i->addr) 99511ea2515SMilian Wolff p = &(*p)->rb_left; 99655ecd631SDavidlohr Bueso else { 99711ea2515SMilian Wolff p = &(*p)->rb_right; 99855ecd631SDavidlohr Bueso leftmost = false; 99955ecd631SDavidlohr Bueso } 100011ea2515SMilian Wolff } 100111ea2515SMilian Wolff rb_link_node(&inlines->rb_node, parent, p); 100255ecd631SDavidlohr Bueso rb_insert_color_cached(&inlines->rb_node, tree, leftmost); 100311ea2515SMilian Wolff } 100411ea2515SMilian Wolff 100555ecd631SDavidlohr Bueso struct inline_node *inlines__tree_find(struct rb_root_cached *tree, u64 addr) 100611ea2515SMilian Wolff { 100755ecd631SDavidlohr Bueso struct rb_node *n = tree->rb_root.rb_node; 100811ea2515SMilian Wolff 100911ea2515SMilian Wolff while (n) { 101011ea2515SMilian Wolff struct inline_node *i = rb_entry(n, struct inline_node, 101111ea2515SMilian Wolff rb_node); 101211ea2515SMilian Wolff 101311ea2515SMilian Wolff if (addr < i->addr) 101411ea2515SMilian Wolff n = n->rb_left; 101511ea2515SMilian Wolff else if (addr > i->addr) 101611ea2515SMilian Wolff n = n->rb_right; 101711ea2515SMilian Wolff else 101811ea2515SMilian Wolff return i; 101911ea2515SMilian Wolff } 102011ea2515SMilian Wolff 102111ea2515SMilian Wolff return NULL; 102211ea2515SMilian Wolff } 102311ea2515SMilian Wolff 102455ecd631SDavidlohr Bueso void inlines__tree_delete(struct rb_root_cached *tree) 102511ea2515SMilian Wolff { 102611ea2515SMilian Wolff struct inline_node *pos; 102755ecd631SDavidlohr Bueso struct rb_node *next = rb_first_cached(tree); 102811ea2515SMilian Wolff 102911ea2515SMilian Wolff while (next) { 103011ea2515SMilian Wolff pos = rb_entry(next, struct inline_node, rb_node); 103111ea2515SMilian Wolff next = rb_next(&pos->rb_node); 103255ecd631SDavidlohr Bueso rb_erase_cached(&pos->rb_node, tree); 103311ea2515SMilian Wolff inline_node__delete(pos); 103411ea2515SMilian Wolff } 103511ea2515SMilian Wolff } 1036