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 24701677b9SIan Rogers /* If addr2line doesn't return data for 1 second then timeout. */ 25701677b9SIan 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 } 392e90208e9SIan Rogers pr_debug("addr2line missing ':' in filename split\n"); 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; 402*149ad69eSIan Rogers close(a2l->in); 403*149ad69eSIan Rogers close(a2l->out); 404be8ecc57STony Garnock-Jones } 405be8ecc57STony Garnock-Jones 406be8ecc57STony Garnock-Jones free(a2l); 407be8ecc57STony Garnock-Jones } 408be8ecc57STony Garnock-Jones 409b3801e79SIan Rogers static struct child_process *addr2line_subprocess_init(const char *addr2line_path, 41057594454SIan Rogers const char *binary_path) 411be8ecc57STony Garnock-Jones { 41257594454SIan Rogers const char *argv[] = { 41357594454SIan Rogers addr2line_path ?: "addr2line", 41457594454SIan Rogers "-e", binary_path, 4158dc26b6fSIan Rogers "-a", "-i", "-f", NULL 41657594454SIan Rogers }; 417b3801e79SIan Rogers struct child_process *a2l = zalloc(sizeof(*a2l)); 418be8ecc57STony Garnock-Jones int start_command_status = 0; 419be8ecc57STony Garnock-Jones 420b3801e79SIan Rogers if (a2l == NULL) { 421b3801e79SIan Rogers pr_err("Failed to allocate memory for addr2line"); 422b3801e79SIan Rogers return NULL; 423b3801e79SIan Rogers } 424be8ecc57STony Garnock-Jones 425b3801e79SIan Rogers a2l->pid = -1; 426b3801e79SIan Rogers a2l->in = -1; 427b3801e79SIan Rogers a2l->out = -1; 428b3801e79SIan Rogers a2l->no_stderr = 1; 429be8ecc57STony Garnock-Jones 430b3801e79SIan Rogers a2l->argv = argv; 431b3801e79SIan Rogers start_command_status = start_command(a2l); 432b3801e79SIan Rogers a2l->argv = NULL; /* it's not used after start_command; avoid dangling pointers */ 433be8ecc57STony Garnock-Jones 434be8ecc57STony Garnock-Jones if (start_command_status != 0) { 43557594454SIan Rogers pr_warning("could not start addr2line (%s) for %s: start_command return code %d\n", 43657594454SIan Rogers addr2line_path, binary_path, start_command_status); 437be8ecc57STony Garnock-Jones addr2line_subprocess_cleanup(a2l); 438be8ecc57STony Garnock-Jones return NULL; 439be8ecc57STony Garnock-Jones } 440be8ecc57STony Garnock-Jones 441b3801e79SIan Rogers return a2l; 442b3801e79SIan Rogers } 443b3801e79SIan Rogers 4442c4b9280SIan Rogers enum a2l_style { 4452c4b9280SIan Rogers BROKEN, 4462c4b9280SIan Rogers GNU_BINUTILS, 4472c4b9280SIan Rogers LLVM, 4482c4b9280SIan Rogers }; 4492c4b9280SIan Rogers 450c7a0023aSIan Rogers static enum a2l_style addr2line_configure(struct child_process *a2l, const char *dso_name) 4512c4b9280SIan Rogers { 4522c4b9280SIan Rogers static bool cached; 4532c4b9280SIan Rogers static enum a2l_style style; 4542c4b9280SIan Rogers 4552c4b9280SIan Rogers if (!cached) { 4562c4b9280SIan Rogers char buf[128]; 4572c4b9280SIan Rogers struct io io; 4582c4b9280SIan Rogers int ch; 459c7a0023aSIan Rogers int lines; 4602c4b9280SIan Rogers 4612c4b9280SIan Rogers if (write(a2l->in, ",\n", 2) != 2) 4622c4b9280SIan Rogers return BROKEN; 4632c4b9280SIan Rogers 4642c4b9280SIan Rogers io__init(&io, a2l->out, buf, sizeof(buf)); 4652c4b9280SIan Rogers ch = io__get_char(&io); 4662c4b9280SIan Rogers if (ch == ',') { 4672c4b9280SIan Rogers style = LLVM; 4682c4b9280SIan Rogers cached = true; 469c7a0023aSIan Rogers lines = 1; 470e90208e9SIan Rogers pr_debug("Detected LLVM addr2line style\n"); 4718dc26b6fSIan Rogers } else if (ch == '0') { 4722c4b9280SIan Rogers style = GNU_BINUTILS; 4732c4b9280SIan Rogers cached = true; 4748dc26b6fSIan Rogers lines = 3; 475e90208e9SIan Rogers pr_debug("Detected binutils addr2line style\n"); 4762c4b9280SIan Rogers } else { 477c7a0023aSIan Rogers if (!symbol_conf.disable_add2line_warn) { 478c7a0023aSIan Rogers char *output = NULL; 479c7a0023aSIan Rogers size_t output_len; 480c7a0023aSIan Rogers 481c7a0023aSIan Rogers io__getline(&io, &output, &output_len); 482c7a0023aSIan Rogers pr_warning("%s %s: addr2line configuration failed\n", 483c7a0023aSIan Rogers __func__, dso_name); 484c7a0023aSIan Rogers pr_warning("\t%c%s", ch, output); 4852c4b9280SIan Rogers } 486e90208e9SIan Rogers pr_debug("Unknown/broken addr2line style\n"); 487c7a0023aSIan Rogers return BROKEN; 488c7a0023aSIan Rogers } 489c7a0023aSIan Rogers while (lines) { 4902c4b9280SIan Rogers ch = io__get_char(&io); 491c7a0023aSIan Rogers if (ch <= 0) 492c7a0023aSIan Rogers break; 493c7a0023aSIan Rogers if (ch == '\n') 494c7a0023aSIan Rogers lines--; 4952c4b9280SIan Rogers } 49675a616c6SIan Rogers /* Ignore SIGPIPE in the event addr2line exits. */ 49775a616c6SIan Rogers signal(SIGPIPE, SIG_IGN); 4982c4b9280SIan Rogers } 4992c4b9280SIan Rogers return style; 5002c4b9280SIan Rogers } 5012c4b9280SIan Rogers 502b3801e79SIan Rogers static int read_addr2line_record(struct io *io, 5032c4b9280SIan Rogers enum a2l_style style, 504e90208e9SIan Rogers const char *dso_name, 505e90208e9SIan Rogers u64 addr, 506e90208e9SIan Rogers bool first, 507be8ecc57STony Garnock-Jones char **function, 508be8ecc57STony Garnock-Jones char **filename, 509be8ecc57STony Garnock-Jones unsigned int *line_nr) 510be8ecc57STony Garnock-Jones { 511be8ecc57STony Garnock-Jones /* 512be8ecc57STony Garnock-Jones * Returns: 513be8ecc57STony Garnock-Jones * -1 ==> error 514be8ecc57STony Garnock-Jones * 0 ==> sentinel (or other ill-formed) record read 515be8ecc57STony Garnock-Jones * 1 ==> a genuine record read 516be8ecc57STony Garnock-Jones */ 517be8ecc57STony Garnock-Jones char *line = NULL; 518be8ecc57STony Garnock-Jones size_t line_len = 0; 519be8ecc57STony Garnock-Jones unsigned int dummy_line_nr = 0; 520be8ecc57STony Garnock-Jones int ret = -1; 521be8ecc57STony Garnock-Jones 522be8ecc57STony Garnock-Jones if (function != NULL) 523be8ecc57STony Garnock-Jones zfree(function); 524be8ecc57STony Garnock-Jones 525be8ecc57STony Garnock-Jones if (filename != NULL) 526be8ecc57STony Garnock-Jones zfree(filename); 527be8ecc57STony Garnock-Jones 528be8ecc57STony Garnock-Jones if (line_nr != NULL) 529be8ecc57STony Garnock-Jones *line_nr = 0; 530be8ecc57STony Garnock-Jones 5318dc26b6fSIan Rogers /* 532e90208e9SIan Rogers * Read the first line. Without an error this will be: 533e90208e9SIan Rogers * - for the first line an address like 0x1234, 534e90208e9SIan Rogers * - the binutils sentinel 0x0000000000000000, 535e90208e9SIan Rogers * - the llvm-addr2line the sentinel ',' character, 536e90208e9SIan Rogers * - the function name line for an inlined function. 5378dc26b6fSIan Rogers */ 538b3801e79SIan Rogers if (io__getline(io, &line, &line_len) < 0 || !line_len) 539be8ecc57STony Garnock-Jones goto error; 5402c4b9280SIan Rogers 541e90208e9SIan Rogers pr_debug("%s %s: addr2line read address for sentinel: %s", __func__, dso_name, line); 542e90208e9SIan Rogers if (style == LLVM && line_len == 2 && line[0] == ',') { 543e90208e9SIan Rogers /* Found the llvm-addr2line sentinel character. */ 5442c4b9280SIan Rogers zfree(&line); 5452c4b9280SIan Rogers return 0; 546e90208e9SIan Rogers } else if (style == GNU_BINUTILS && (!first || addr != 0)) { 5478dc26b6fSIan Rogers int zero_count = 0, non_zero_count = 0; 548e90208e9SIan Rogers /* 549e90208e9SIan Rogers * Check for binutils sentinel ignoring it for the case the 550e90208e9SIan Rogers * requested address is 0. 551e90208e9SIan Rogers */ 5528dc26b6fSIan Rogers 553e90208e9SIan Rogers /* A given address should always start 0x. */ 554e90208e9SIan Rogers if (line_len >= 2 || line[0] != '0' || line[1] != 'x') { 5558dc26b6fSIan Rogers for (size_t i = 2; i < line_len; i++) { 5568dc26b6fSIan Rogers if (line[i] == '0') 5578dc26b6fSIan Rogers zero_count++; 5588dc26b6fSIan Rogers else if (line[i] != '\n') 5598dc26b6fSIan Rogers non_zero_count++; 5608dc26b6fSIan Rogers } 5618dc26b6fSIan Rogers if (!non_zero_count) { 5628dc26b6fSIan Rogers int ch; 5638dc26b6fSIan Rogers 564e90208e9SIan Rogers if (first && !zero_count) { 5658dc26b6fSIan Rogers /* Line was erroneous just '0x'. */ 5668dc26b6fSIan Rogers goto error; 5678dc26b6fSIan Rogers } 5688dc26b6fSIan Rogers /* 5698dc26b6fSIan Rogers * Line was 0x0..0, the sentinel for binutils. Remove 5708dc26b6fSIan Rogers * the function and filename lines. 5718dc26b6fSIan Rogers */ 5728dc26b6fSIan Rogers zfree(&line); 5738dc26b6fSIan Rogers do { 5748dc26b6fSIan Rogers ch = io__get_char(io); 5758dc26b6fSIan Rogers } while (ch > 0 && ch != '\n'); 5768dc26b6fSIan Rogers do { 5778dc26b6fSIan Rogers ch = io__get_char(io); 5788dc26b6fSIan Rogers } while (ch > 0 && ch != '\n'); 5798dc26b6fSIan Rogers return 0; 5808dc26b6fSIan Rogers } 5818dc26b6fSIan Rogers } 582e90208e9SIan Rogers } 583e90208e9SIan Rogers /* Read the second function name line (if inline data then this is the first line). */ 584e90208e9SIan Rogers if (first && (io__getline(io, &line, &line_len) < 0 || !line_len)) 5858dc26b6fSIan Rogers goto error; 5862c4b9280SIan Rogers 587e90208e9SIan Rogers pr_debug("%s %s: addr2line read line: %s", __func__, dso_name, line); 588be8ecc57STony Garnock-Jones if (function != NULL) 589be8ecc57STony Garnock-Jones *function = strdup(strim(line)); 590be8ecc57STony Garnock-Jones 591be8ecc57STony Garnock-Jones zfree(&line); 592be8ecc57STony Garnock-Jones line_len = 0; 593be8ecc57STony Garnock-Jones 5948dc26b6fSIan Rogers /* Read the third filename and line number line. */ 595b3801e79SIan Rogers if (io__getline(io, &line, &line_len) < 0 || !line_len) 596be8ecc57STony Garnock-Jones goto error; 597be8ecc57STony Garnock-Jones 598e90208e9SIan Rogers pr_debug("%s %s: addr2line filename:number : %s", __func__, dso_name, line); 5992c4b9280SIan Rogers if (filename_split(line, line_nr == NULL ? &dummy_line_nr : line_nr) == 0 && 6002c4b9280SIan Rogers style == GNU_BINUTILS) { 601be8ecc57STony Garnock-Jones ret = 0; 602be8ecc57STony Garnock-Jones goto error; 603be8ecc57STony Garnock-Jones } 604be8ecc57STony Garnock-Jones 605be8ecc57STony Garnock-Jones if (filename != NULL) 606be8ecc57STony Garnock-Jones *filename = strdup(line); 607be8ecc57STony Garnock-Jones 608be8ecc57STony Garnock-Jones zfree(&line); 609be8ecc57STony Garnock-Jones line_len = 0; 610be8ecc57STony Garnock-Jones 611be8ecc57STony Garnock-Jones return 1; 612be8ecc57STony Garnock-Jones 613be8ecc57STony Garnock-Jones error: 614be8ecc57STony Garnock-Jones free(line); 615be8ecc57STony Garnock-Jones if (function != NULL) 616be8ecc57STony Garnock-Jones zfree(function); 617be8ecc57STony Garnock-Jones if (filename != NULL) 618be8ecc57STony Garnock-Jones zfree(filename); 619f048d548SNamhyung Kim return ret; 620f048d548SNamhyung Kim } 621454ff00fSAdrian Hunter 622be8ecc57STony Garnock-Jones static int inline_list__append_record(struct dso *dso, 623be8ecc57STony Garnock-Jones struct inline_node *node, 624be8ecc57STony Garnock-Jones struct symbol *sym, 625be8ecc57STony Garnock-Jones const char *function, 626be8ecc57STony Garnock-Jones const char *filename, 627be8ecc57STony Garnock-Jones unsigned int line_nr) 628454ff00fSAdrian Hunter { 629be8ecc57STony Garnock-Jones struct symbol *inline_sym = new_inline_sym(dso, sym, function); 630be8ecc57STony Garnock-Jones 631be8ecc57STony Garnock-Jones return inline_list__append(inline_sym, srcline_from_fileline(filename, line_nr), node); 632454ff00fSAdrian Hunter } 633454ff00fSAdrian Hunter 634be8ecc57STony Garnock-Jones static int addr2line(const char *dso_name, u64 addr, 635be8ecc57STony Garnock-Jones char **file, unsigned int *line_nr, 636be8ecc57STony Garnock-Jones struct dso *dso, 637be8ecc57STony Garnock-Jones bool unwind_inlines, 638be8ecc57STony Garnock-Jones struct inline_node *node, 639be8ecc57STony Garnock-Jones struct symbol *sym __maybe_unused) 640be8ecc57STony Garnock-Jones { 641b3801e79SIan Rogers struct child_process *a2l = dso->a2l; 642be8ecc57STony Garnock-Jones char *record_function = NULL; 643be8ecc57STony Garnock-Jones char *record_filename = NULL; 644be8ecc57STony Garnock-Jones unsigned int record_line_nr = 0; 645be8ecc57STony Garnock-Jones int record_status = -1; 646be8ecc57STony Garnock-Jones int ret = 0; 647be8ecc57STony Garnock-Jones size_t inline_count = 0; 648b3801e79SIan Rogers int len; 649b3801e79SIan Rogers char buf[128]; 650b3801e79SIan Rogers ssize_t written; 651701677b9SIan Rogers struct io io = { .eof = false }; 6522c4b9280SIan Rogers enum a2l_style a2l_style; 653be8ecc57STony Garnock-Jones 654be8ecc57STony Garnock-Jones if (!a2l) { 6553b27222dSNamhyung Kim if (!filename__has_section(dso_name, ".debug_line")) 6563b27222dSNamhyung Kim goto out; 6573b27222dSNamhyung Kim 658e90208e9SIan Rogers dso->a2l = addr2line_subprocess_init(symbol_conf.addr2line_path, dso_name); 659be8ecc57STony Garnock-Jones a2l = dso->a2l; 660be8ecc57STony Garnock-Jones } 661be8ecc57STony Garnock-Jones 662be8ecc57STony Garnock-Jones if (a2l == NULL) { 663be8ecc57STony Garnock-Jones if (!symbol_conf.disable_add2line_warn) 664be8ecc57STony Garnock-Jones pr_warning("%s %s: addr2line_subprocess_init failed\n", __func__, dso_name); 665be8ecc57STony Garnock-Jones goto out; 666be8ecc57STony Garnock-Jones } 667c7a0023aSIan Rogers a2l_style = addr2line_configure(a2l, dso_name); 668c7a0023aSIan Rogers if (a2l_style == BROKEN) 6692c4b9280SIan Rogers goto out; 670be8ecc57STony Garnock-Jones 671be8ecc57STony Garnock-Jones /* 672e90208e9SIan Rogers * Send our request and then *deliberately* send something that can't be 673e90208e9SIan Rogers * interpreted as a valid address to ask addr2line about (namely, 674e90208e9SIan Rogers * ","). This causes addr2line to first write out the answer to our 675e90208e9SIan Rogers * request, in an unbounded/unknown number of records, and then to write 676e90208e9SIan Rogers * out the lines "0x0...0", "??" and "??:0", for GNU binutils, or "," 677e90208e9SIan Rogers * for llvm-addr2line, so that we can detect when it has finished giving 678e90208e9SIan Rogers * us anything useful. 679be8ecc57STony Garnock-Jones */ 680b3801e79SIan Rogers len = snprintf(buf, sizeof(buf), "%016"PRIx64"\n,\n", addr); 681b3801e79SIan Rogers written = len > 0 ? write(a2l->in, buf, len) : -1; 682b3801e79SIan Rogers if (written != len) { 683d5e33ce0SNamhyung Kim if (!symbol_conf.disable_add2line_warn) 684be8ecc57STony Garnock-Jones pr_warning("%s %s: could not send request\n", __func__, dso_name); 685be8ecc57STony Garnock-Jones goto out; 686be8ecc57STony Garnock-Jones } 687b3801e79SIan Rogers io__init(&io, a2l->out, buf, sizeof(buf)); 688701677b9SIan Rogers io.timeout_ms = addr2line_timeout_ms; 689e90208e9SIan Rogers switch (read_addr2line_record(&io, a2l_style, dso_name, addr, /*first=*/true, 6902c4b9280SIan Rogers &record_function, &record_filename, &record_line_nr)) { 691be8ecc57STony Garnock-Jones case -1: 692d5e33ce0SNamhyung Kim if (!symbol_conf.disable_add2line_warn) 693be8ecc57STony Garnock-Jones pr_warning("%s %s: could not read first record\n", __func__, dso_name); 694be8ecc57STony Garnock-Jones goto out; 695be8ecc57STony Garnock-Jones case 0: 696be8ecc57STony Garnock-Jones /* 6978dc26b6fSIan Rogers * The first record was invalid, so return failure, but first 6988dc26b6fSIan Rogers * read another record, since we sent a sentinel ',' for the 699e90208e9SIan Rogers * sake of detected the last inlined function. Treat this as the 700e90208e9SIan Rogers * first of a record as the ',' generates a new start with GNU 701e90208e9SIan Rogers * binutils, also force a non-zero address as we're no longer 702e90208e9SIan Rogers * reading that record. 703be8ecc57STony Garnock-Jones */ 704e90208e9SIan Rogers switch (read_addr2line_record(&io, a2l_style, dso_name, 705e90208e9SIan Rogers /*addr=*/1, /*first=*/true, 706e90208e9SIan Rogers NULL, NULL, NULL)) { 707be8ecc57STony Garnock-Jones case -1: 708d5e33ce0SNamhyung Kim if (!symbol_conf.disable_add2line_warn) 709e90208e9SIan Rogers pr_warning("%s %s: could not read sentinel record\n", 710d5e33ce0SNamhyung Kim __func__, dso_name); 711be8ecc57STony Garnock-Jones break; 712be8ecc57STony Garnock-Jones case 0: 713e90208e9SIan Rogers /* The sentinel as expected. */ 714be8ecc57STony Garnock-Jones break; 715be8ecc57STony Garnock-Jones default: 716d5e33ce0SNamhyung Kim if (!symbol_conf.disable_add2line_warn) 717be8ecc57STony Garnock-Jones pr_warning("%s %s: unexpected record instead of sentinel", 718be8ecc57STony Garnock-Jones __func__, dso_name); 719be8ecc57STony Garnock-Jones break; 720be8ecc57STony Garnock-Jones } 721be8ecc57STony Garnock-Jones goto out; 722be8ecc57STony Garnock-Jones default: 723e90208e9SIan Rogers /* First record as expected. */ 724be8ecc57STony Garnock-Jones break; 725be8ecc57STony Garnock-Jones } 726be8ecc57STony Garnock-Jones 727be8ecc57STony Garnock-Jones if (file) { 728be8ecc57STony Garnock-Jones *file = strdup(record_filename); 729be8ecc57STony Garnock-Jones ret = 1; 730be8ecc57STony Garnock-Jones } 731be8ecc57STony Garnock-Jones if (line_nr) 732be8ecc57STony Garnock-Jones *line_nr = record_line_nr; 733be8ecc57STony Garnock-Jones 734be8ecc57STony Garnock-Jones if (unwind_inlines) { 735be8ecc57STony Garnock-Jones if (node && inline_list__append_record(dso, node, sym, 736be8ecc57STony Garnock-Jones record_function, 737be8ecc57STony Garnock-Jones record_filename, 738be8ecc57STony Garnock-Jones record_line_nr)) { 739be8ecc57STony Garnock-Jones ret = 0; 740be8ecc57STony Garnock-Jones goto out; 741be8ecc57STony Garnock-Jones } 742be8ecc57STony Garnock-Jones } 743be8ecc57STony Garnock-Jones 744e90208e9SIan Rogers /* 745e90208e9SIan Rogers * We have to read the records even if we don't care about the inline 746e90208e9SIan Rogers * info. This isn't the first record and force the address to non-zero 747e90208e9SIan Rogers * as we're reading records beyond the first. 748e90208e9SIan Rogers */ 749b3801e79SIan Rogers while ((record_status = read_addr2line_record(&io, 7502c4b9280SIan Rogers a2l_style, 751e90208e9SIan Rogers dso_name, 752e90208e9SIan Rogers /*addr=*/1, 753e90208e9SIan Rogers /*first=*/false, 754be8ecc57STony Garnock-Jones &record_function, 755be8ecc57STony Garnock-Jones &record_filename, 756be8ecc57STony Garnock-Jones &record_line_nr)) == 1) { 757be8ecc57STony Garnock-Jones if (unwind_inlines && node && inline_count++ < MAX_INLINE_NEST) { 758be8ecc57STony Garnock-Jones if (inline_list__append_record(dso, node, sym, 759be8ecc57STony Garnock-Jones record_function, 760be8ecc57STony Garnock-Jones record_filename, 761be8ecc57STony Garnock-Jones record_line_nr)) { 762be8ecc57STony Garnock-Jones ret = 0; 763be8ecc57STony Garnock-Jones goto out; 764be8ecc57STony Garnock-Jones } 765be8ecc57STony Garnock-Jones ret = 1; /* found at least one inline frame */ 766be8ecc57STony Garnock-Jones } 767be8ecc57STony Garnock-Jones } 768be8ecc57STony Garnock-Jones 769be8ecc57STony Garnock-Jones out: 770be8ecc57STony Garnock-Jones free(record_function); 771be8ecc57STony Garnock-Jones free(record_filename); 772701677b9SIan Rogers if (io.eof) { 773701677b9SIan Rogers dso->a2l = NULL; 774701677b9SIan Rogers addr2line_subprocess_cleanup(a2l); 775701677b9SIan Rogers } 776be8ecc57STony Garnock-Jones return ret; 777be8ecc57STony Garnock-Jones } 778be8ecc57STony Garnock-Jones 779be8ecc57STony Garnock-Jones void dso__free_a2l(struct dso *dso) 780be8ecc57STony Garnock-Jones { 781b3801e79SIan Rogers struct child_process *a2l = dso->a2l; 782be8ecc57STony Garnock-Jones 783be8ecc57STony Garnock-Jones if (!a2l) 784be8ecc57STony Garnock-Jones return; 785be8ecc57STony Garnock-Jones 786be8ecc57STony Garnock-Jones addr2line_subprocess_cleanup(a2l); 787be8ecc57STony Garnock-Jones 788be8ecc57STony Garnock-Jones dso->a2l = NULL; 789be8ecc57STony Garnock-Jones } 790be8ecc57STony Garnock-Jones 791be8ecc57STony Garnock-Jones #endif /* HAVE_LIBBFD_SUPPORT */ 792be8ecc57STony Garnock-Jones 793a64489c5SJin Yao static struct inline_node *addr2inlines(const char *dso_name, u64 addr, 794be8ecc57STony Garnock-Jones struct dso *dso, struct symbol *sym) 795a64489c5SJin Yao { 796a64489c5SJin Yao struct inline_node *node; 797a64489c5SJin Yao 798a64489c5SJin Yao node = zalloc(sizeof(*node)); 799a64489c5SJin Yao if (node == NULL) { 800a64489c5SJin Yao perror("not enough memory for the inline node"); 801be8ecc57STony Garnock-Jones return NULL; 802a64489c5SJin Yao } 803a64489c5SJin Yao 804a64489c5SJin Yao INIT_LIST_HEAD(&node->val); 805a64489c5SJin Yao node->addr = addr; 806a64489c5SJin Yao 807be8ecc57STony Garnock-Jones addr2line(dso_name, addr, NULL, NULL, dso, true, node, sym); 808a64489c5SJin Yao return node; 809a64489c5SJin Yao } 810a64489c5SJin Yao 811906049c8SAdrian Hunter /* 812906049c8SAdrian Hunter * Number of addr2line failures (without success) before disabling it for that 813906049c8SAdrian Hunter * dso. 814906049c8SAdrian Hunter */ 815906049c8SAdrian Hunter #define A2L_FAIL_LIMIT 123 816906049c8SAdrian Hunter 8172f84b42bSAndi Kleen char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym, 818935f5a9dSJin Yao bool show_sym, bool show_addr, bool unwind_inlines, 819935f5a9dSJin Yao u64 ip) 820f048d548SNamhyung Kim { 821a949fffbSDavid Ahern char *file = NULL; 822a949fffbSDavid Ahern unsigned line = 0; 8232cc9d0efSNamhyung Kim char *srcline; 824bf4414aeSArnaldo Carvalho de Melo const char *dso_name; 825f048d548SNamhyung Kim 8262cc9d0efSNamhyung Kim if (!dso->has_srcline) 82723f0981bSAndi Kleen goto out; 8282cc9d0efSNamhyung Kim 8295580338dSJin Yao dso_name = dso__name(dso); 8305580338dSJin Yao if (dso_name == NULL) 83158d91a00SNamhyung Kim goto out; 83258d91a00SNamhyung Kim 833fea0cf84SMilian Wolff if (!addr2line(dso_name, addr, &file, &line, dso, 834fea0cf84SMilian Wolff unwind_inlines, NULL, sym)) 83558d91a00SNamhyung Kim goto out; 836f048d548SNamhyung Kim 8372be8832fSMilian Wolff srcline = srcline_from_fileline(file, line); 838906049c8SAdrian Hunter free(file); 8392be8832fSMilian Wolff 8402be8832fSMilian Wolff if (!srcline) 841906049c8SAdrian Hunter goto out; 842906049c8SAdrian Hunter 843906049c8SAdrian Hunter dso->a2l_fails = 0; 844f048d548SNamhyung Kim 845f048d548SNamhyung Kim return srcline; 8462cc9d0efSNamhyung Kim 8472cc9d0efSNamhyung Kim out: 848906049c8SAdrian Hunter if (dso->a2l_fails && ++dso->a2l_fails > A2L_FAIL_LIMIT) { 8492cc9d0efSNamhyung Kim dso->has_srcline = 0; 850454ff00fSAdrian Hunter dso__free_a2l(dso); 851906049c8SAdrian Hunter } 8525dfa210eSMilian Wolff 8535dfa210eSMilian Wolff if (!show_addr) 8545dfa210eSMilian Wolff return (show_sym && sym) ? 855ea335ef3SNamhyung Kim strndup(sym->name, sym->namelen) : SRCLINE_UNKNOWN; 8565dfa210eSMilian Wolff 85785c116a6SAndi Kleen if (sym) { 858ac931f87SWang Nan if (asprintf(&srcline, "%s+%" PRIu64, show_sym ? sym->name : "", 859935f5a9dSJin Yao ip - sym->start) < 0) 86085c116a6SAndi Kleen return SRCLINE_UNKNOWN; 861ac931f87SWang Nan } else if (asprintf(&srcline, "%s[%" PRIx64 "]", dso->short_name, addr) < 0) 8622cc9d0efSNamhyung Kim return SRCLINE_UNKNOWN; 86323f0981bSAndi Kleen return srcline; 864f048d548SNamhyung Kim } 865f048d548SNamhyung Kim 866dd2e18e9SAndi Kleen /* Returns filename and fills in line number in line */ 867dd2e18e9SAndi Kleen char *get_srcline_split(struct dso *dso, u64 addr, unsigned *line) 868dd2e18e9SAndi Kleen { 869dd2e18e9SAndi Kleen char *file = NULL; 870dd2e18e9SAndi Kleen const char *dso_name; 871dd2e18e9SAndi Kleen 872dd2e18e9SAndi Kleen if (!dso->has_srcline) 873dd2e18e9SAndi Kleen goto out; 874dd2e18e9SAndi Kleen 875dd2e18e9SAndi Kleen dso_name = dso__name(dso); 876dd2e18e9SAndi Kleen if (dso_name == NULL) 877dd2e18e9SAndi Kleen goto out; 878dd2e18e9SAndi Kleen 879dd2e18e9SAndi Kleen if (!addr2line(dso_name, addr, &file, line, dso, true, NULL, NULL)) 880dd2e18e9SAndi Kleen goto out; 881dd2e18e9SAndi Kleen 882dd2e18e9SAndi Kleen dso->a2l_fails = 0; 883dd2e18e9SAndi Kleen return file; 884dd2e18e9SAndi Kleen 885dd2e18e9SAndi Kleen out: 886dd2e18e9SAndi Kleen if (dso->a2l_fails && ++dso->a2l_fails > A2L_FAIL_LIMIT) { 887dd2e18e9SAndi Kleen dso->has_srcline = 0; 888dd2e18e9SAndi Kleen dso__free_a2l(dso); 889dd2e18e9SAndi Kleen } 890dd2e18e9SAndi Kleen 891dd2e18e9SAndi Kleen return NULL; 892dd2e18e9SAndi Kleen } 893dd2e18e9SAndi Kleen 894625db36eSIan Rogers void zfree_srcline(char **srcline) 895f048d548SNamhyung Kim { 896625db36eSIan Rogers if (*srcline == NULL) 897625db36eSIan Rogers return; 898625db36eSIan Rogers 899922db21dSArnaldo Carvalho de Melo if (*srcline != SRCLINE_UNKNOWN) 900625db36eSIan Rogers free(*srcline); 901625db36eSIan Rogers 902625db36eSIan Rogers *srcline = NULL; 903f048d548SNamhyung Kim } 9042f84b42bSAndi Kleen 9052f84b42bSAndi Kleen char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym, 906935f5a9dSJin Yao bool show_sym, bool show_addr, u64 ip) 9072f84b42bSAndi Kleen { 908935f5a9dSJin Yao return __get_srcline(dso, addr, sym, show_sym, show_addr, false, ip); 9092f84b42bSAndi Kleen } 910a64489c5SJin Yao 91121ac9d54SMilian Wolff struct srcline_node { 91221ac9d54SMilian Wolff u64 addr; 91321ac9d54SMilian Wolff char *srcline; 91421ac9d54SMilian Wolff struct rb_node rb_node; 91521ac9d54SMilian Wolff }; 91621ac9d54SMilian Wolff 91755ecd631SDavidlohr Bueso void srcline__tree_insert(struct rb_root_cached *tree, u64 addr, char *srcline) 91821ac9d54SMilian Wolff { 91955ecd631SDavidlohr Bueso struct rb_node **p = &tree->rb_root.rb_node; 92021ac9d54SMilian Wolff struct rb_node *parent = NULL; 92121ac9d54SMilian Wolff struct srcline_node *i, *node; 92255ecd631SDavidlohr Bueso bool leftmost = true; 92321ac9d54SMilian Wolff 92421ac9d54SMilian Wolff node = zalloc(sizeof(struct srcline_node)); 92521ac9d54SMilian Wolff if (!node) { 92621ac9d54SMilian Wolff perror("not enough memory for the srcline node"); 92721ac9d54SMilian Wolff return; 92821ac9d54SMilian Wolff } 92921ac9d54SMilian Wolff 93021ac9d54SMilian Wolff node->addr = addr; 93121ac9d54SMilian Wolff node->srcline = srcline; 93221ac9d54SMilian Wolff 93321ac9d54SMilian Wolff while (*p != NULL) { 93421ac9d54SMilian Wolff parent = *p; 93521ac9d54SMilian Wolff i = rb_entry(parent, struct srcline_node, rb_node); 93621ac9d54SMilian Wolff if (addr < i->addr) 93721ac9d54SMilian Wolff p = &(*p)->rb_left; 93855ecd631SDavidlohr Bueso else { 93921ac9d54SMilian Wolff p = &(*p)->rb_right; 94055ecd631SDavidlohr Bueso leftmost = false; 94155ecd631SDavidlohr Bueso } 94221ac9d54SMilian Wolff } 94321ac9d54SMilian Wolff rb_link_node(&node->rb_node, parent, p); 94455ecd631SDavidlohr Bueso rb_insert_color_cached(&node->rb_node, tree, leftmost); 94521ac9d54SMilian Wolff } 94621ac9d54SMilian Wolff 94755ecd631SDavidlohr Bueso char *srcline__tree_find(struct rb_root_cached *tree, u64 addr) 94821ac9d54SMilian Wolff { 94955ecd631SDavidlohr Bueso struct rb_node *n = tree->rb_root.rb_node; 95021ac9d54SMilian Wolff 95121ac9d54SMilian Wolff while (n) { 95221ac9d54SMilian Wolff struct srcline_node *i = rb_entry(n, struct srcline_node, 95321ac9d54SMilian Wolff rb_node); 95421ac9d54SMilian Wolff 95521ac9d54SMilian Wolff if (addr < i->addr) 95621ac9d54SMilian Wolff n = n->rb_left; 95721ac9d54SMilian Wolff else if (addr > i->addr) 95821ac9d54SMilian Wolff n = n->rb_right; 95921ac9d54SMilian Wolff else 96021ac9d54SMilian Wolff return i->srcline; 96121ac9d54SMilian Wolff } 96221ac9d54SMilian Wolff 96321ac9d54SMilian Wolff return NULL; 96421ac9d54SMilian Wolff } 96521ac9d54SMilian Wolff 96655ecd631SDavidlohr Bueso void srcline__tree_delete(struct rb_root_cached *tree) 96721ac9d54SMilian Wolff { 96821ac9d54SMilian Wolff struct srcline_node *pos; 96955ecd631SDavidlohr Bueso struct rb_node *next = rb_first_cached(tree); 97021ac9d54SMilian Wolff 97121ac9d54SMilian Wolff while (next) { 97221ac9d54SMilian Wolff pos = rb_entry(next, struct srcline_node, rb_node); 97321ac9d54SMilian Wolff next = rb_next(&pos->rb_node); 97455ecd631SDavidlohr Bueso rb_erase_cached(&pos->rb_node, tree); 975625db36eSIan Rogers zfree_srcline(&pos->srcline); 97621ac9d54SMilian Wolff zfree(&pos); 97721ac9d54SMilian Wolff } 97821ac9d54SMilian Wolff } 97921ac9d54SMilian Wolff 980fea0cf84SMilian Wolff struct inline_node *dso__parse_addr_inlines(struct dso *dso, u64 addr, 981fea0cf84SMilian Wolff struct symbol *sym) 982a64489c5SJin Yao { 983a64489c5SJin Yao const char *dso_name; 984a64489c5SJin Yao 985a64489c5SJin Yao dso_name = dso__name(dso); 986a64489c5SJin Yao if (dso_name == NULL) 987a64489c5SJin Yao return NULL; 988a64489c5SJin Yao 989fea0cf84SMilian Wolff return addr2inlines(dso_name, addr, dso, sym); 990a64489c5SJin Yao } 991a64489c5SJin Yao 992a64489c5SJin Yao void inline_node__delete(struct inline_node *node) 993a64489c5SJin Yao { 994a64489c5SJin Yao struct inline_list *ilist, *tmp; 995a64489c5SJin Yao 996a64489c5SJin Yao list_for_each_entry_safe(ilist, tmp, &node->val, list) { 997a64489c5SJin Yao list_del_init(&ilist->list); 998625db36eSIan Rogers zfree_srcline(&ilist->srcline); 999fea0cf84SMilian Wolff /* only the inlined symbols are owned by the list */ 1000fea0cf84SMilian Wolff if (ilist->symbol && ilist->symbol->inlined) 1001fea0cf84SMilian Wolff symbol__delete(ilist->symbol); 1002a64489c5SJin Yao free(ilist); 1003a64489c5SJin Yao } 1004a64489c5SJin Yao 1005a64489c5SJin Yao free(node); 1006a64489c5SJin Yao } 100711ea2515SMilian Wolff 100855ecd631SDavidlohr Bueso void inlines__tree_insert(struct rb_root_cached *tree, 100955ecd631SDavidlohr Bueso struct inline_node *inlines) 101011ea2515SMilian Wolff { 101155ecd631SDavidlohr Bueso struct rb_node **p = &tree->rb_root.rb_node; 101211ea2515SMilian Wolff struct rb_node *parent = NULL; 101311ea2515SMilian Wolff const u64 addr = inlines->addr; 101411ea2515SMilian Wolff struct inline_node *i; 101555ecd631SDavidlohr Bueso bool leftmost = true; 101611ea2515SMilian Wolff 101711ea2515SMilian Wolff while (*p != NULL) { 101811ea2515SMilian Wolff parent = *p; 101911ea2515SMilian Wolff i = rb_entry(parent, struct inline_node, rb_node); 102011ea2515SMilian Wolff if (addr < i->addr) 102111ea2515SMilian Wolff p = &(*p)->rb_left; 102255ecd631SDavidlohr Bueso else { 102311ea2515SMilian Wolff p = &(*p)->rb_right; 102455ecd631SDavidlohr Bueso leftmost = false; 102555ecd631SDavidlohr Bueso } 102611ea2515SMilian Wolff } 102711ea2515SMilian Wolff rb_link_node(&inlines->rb_node, parent, p); 102855ecd631SDavidlohr Bueso rb_insert_color_cached(&inlines->rb_node, tree, leftmost); 102911ea2515SMilian Wolff } 103011ea2515SMilian Wolff 103155ecd631SDavidlohr Bueso struct inline_node *inlines__tree_find(struct rb_root_cached *tree, u64 addr) 103211ea2515SMilian Wolff { 103355ecd631SDavidlohr Bueso struct rb_node *n = tree->rb_root.rb_node; 103411ea2515SMilian Wolff 103511ea2515SMilian Wolff while (n) { 103611ea2515SMilian Wolff struct inline_node *i = rb_entry(n, struct inline_node, 103711ea2515SMilian Wolff rb_node); 103811ea2515SMilian Wolff 103911ea2515SMilian Wolff if (addr < i->addr) 104011ea2515SMilian Wolff n = n->rb_left; 104111ea2515SMilian Wolff else if (addr > i->addr) 104211ea2515SMilian Wolff n = n->rb_right; 104311ea2515SMilian Wolff else 104411ea2515SMilian Wolff return i; 104511ea2515SMilian Wolff } 104611ea2515SMilian Wolff 104711ea2515SMilian Wolff return NULL; 104811ea2515SMilian Wolff } 104911ea2515SMilian Wolff 105055ecd631SDavidlohr Bueso void inlines__tree_delete(struct rb_root_cached *tree) 105111ea2515SMilian Wolff { 105211ea2515SMilian Wolff struct inline_node *pos; 105355ecd631SDavidlohr Bueso struct rb_node *next = rb_first_cached(tree); 105411ea2515SMilian Wolff 105511ea2515SMilian Wolff while (next) { 105611ea2515SMilian Wolff pos = rb_entry(next, struct inline_node, rb_node); 105711ea2515SMilian Wolff next = rb_next(&pos->rb_node); 105855ecd631SDavidlohr Bueso rb_erase_cached(&pos->rb_node, tree); 105911ea2515SMilian Wolff inline_node__delete(pos); 106011ea2515SMilian Wolff } 106111ea2515SMilian Wolff } 1062