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 } 392*e90208e9SIan 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; 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; 468*e90208e9SIan Rogers pr_debug("Detected LLVM addr2line style\n"); 4698dc26b6fSIan Rogers } else if (ch == '0') { 4702c4b9280SIan Rogers style = GNU_BINUTILS; 4712c4b9280SIan Rogers cached = true; 4728dc26b6fSIan Rogers lines = 3; 473*e90208e9SIan Rogers pr_debug("Detected binutils addr2line style\n"); 4742c4b9280SIan Rogers } else { 475c7a0023aSIan Rogers if (!symbol_conf.disable_add2line_warn) { 476c7a0023aSIan Rogers char *output = NULL; 477c7a0023aSIan Rogers size_t output_len; 478c7a0023aSIan Rogers 479c7a0023aSIan Rogers io__getline(&io, &output, &output_len); 480c7a0023aSIan Rogers pr_warning("%s %s: addr2line configuration failed\n", 481c7a0023aSIan Rogers __func__, dso_name); 482c7a0023aSIan Rogers pr_warning("\t%c%s", ch, output); 4832c4b9280SIan Rogers } 484*e90208e9SIan Rogers pr_debug("Unknown/broken addr2line style\n"); 485c7a0023aSIan Rogers return BROKEN; 486c7a0023aSIan Rogers } 487c7a0023aSIan Rogers while (lines) { 4882c4b9280SIan Rogers ch = io__get_char(&io); 489c7a0023aSIan Rogers if (ch <= 0) 490c7a0023aSIan Rogers break; 491c7a0023aSIan Rogers if (ch == '\n') 492c7a0023aSIan Rogers lines--; 4932c4b9280SIan Rogers } 49475a616c6SIan Rogers /* Ignore SIGPIPE in the event addr2line exits. */ 49575a616c6SIan Rogers signal(SIGPIPE, SIG_IGN); 4962c4b9280SIan Rogers } 4972c4b9280SIan Rogers return style; 4982c4b9280SIan Rogers } 4992c4b9280SIan Rogers 500b3801e79SIan Rogers static int read_addr2line_record(struct io *io, 5012c4b9280SIan Rogers enum a2l_style style, 502*e90208e9SIan Rogers const char *dso_name, 503*e90208e9SIan Rogers u64 addr, 504*e90208e9SIan Rogers bool first, 505be8ecc57STony Garnock-Jones char **function, 506be8ecc57STony Garnock-Jones char **filename, 507be8ecc57STony Garnock-Jones unsigned int *line_nr) 508be8ecc57STony Garnock-Jones { 509be8ecc57STony Garnock-Jones /* 510be8ecc57STony Garnock-Jones * Returns: 511be8ecc57STony Garnock-Jones * -1 ==> error 512be8ecc57STony Garnock-Jones * 0 ==> sentinel (or other ill-formed) record read 513be8ecc57STony Garnock-Jones * 1 ==> a genuine record read 514be8ecc57STony Garnock-Jones */ 515be8ecc57STony Garnock-Jones char *line = NULL; 516be8ecc57STony Garnock-Jones size_t line_len = 0; 517be8ecc57STony Garnock-Jones unsigned int dummy_line_nr = 0; 518be8ecc57STony Garnock-Jones int ret = -1; 519be8ecc57STony Garnock-Jones 520be8ecc57STony Garnock-Jones if (function != NULL) 521be8ecc57STony Garnock-Jones zfree(function); 522be8ecc57STony Garnock-Jones 523be8ecc57STony Garnock-Jones if (filename != NULL) 524be8ecc57STony Garnock-Jones zfree(filename); 525be8ecc57STony Garnock-Jones 526be8ecc57STony Garnock-Jones if (line_nr != NULL) 527be8ecc57STony Garnock-Jones *line_nr = 0; 528be8ecc57STony Garnock-Jones 5298dc26b6fSIan Rogers /* 530*e90208e9SIan Rogers * Read the first line. Without an error this will be: 531*e90208e9SIan Rogers * - for the first line an address like 0x1234, 532*e90208e9SIan Rogers * - the binutils sentinel 0x0000000000000000, 533*e90208e9SIan Rogers * - the llvm-addr2line the sentinel ',' character, 534*e90208e9SIan Rogers * - the function name line for an inlined function. 5358dc26b6fSIan Rogers */ 536b3801e79SIan Rogers if (io__getline(io, &line, &line_len) < 0 || !line_len) 537be8ecc57STony Garnock-Jones goto error; 5382c4b9280SIan Rogers 539*e90208e9SIan Rogers pr_debug("%s %s: addr2line read address for sentinel: %s", __func__, dso_name, line); 540*e90208e9SIan Rogers if (style == LLVM && line_len == 2 && line[0] == ',') { 541*e90208e9SIan Rogers /* Found the llvm-addr2line sentinel character. */ 5422c4b9280SIan Rogers zfree(&line); 5432c4b9280SIan Rogers return 0; 544*e90208e9SIan Rogers } else if (style == GNU_BINUTILS && (!first || addr != 0)) { 5458dc26b6fSIan Rogers int zero_count = 0, non_zero_count = 0; 546*e90208e9SIan Rogers /* 547*e90208e9SIan Rogers * Check for binutils sentinel ignoring it for the case the 548*e90208e9SIan Rogers * requested address is 0. 549*e90208e9SIan Rogers */ 5508dc26b6fSIan Rogers 551*e90208e9SIan Rogers /* A given address should always start 0x. */ 552*e90208e9SIan Rogers if (line_len >= 2 || line[0] != '0' || line[1] != 'x') { 5538dc26b6fSIan Rogers for (size_t i = 2; i < line_len; i++) { 5548dc26b6fSIan Rogers if (line[i] == '0') 5558dc26b6fSIan Rogers zero_count++; 5568dc26b6fSIan Rogers else if (line[i] != '\n') 5578dc26b6fSIan Rogers non_zero_count++; 5588dc26b6fSIan Rogers } 5598dc26b6fSIan Rogers if (!non_zero_count) { 5608dc26b6fSIan Rogers int ch; 5618dc26b6fSIan Rogers 562*e90208e9SIan Rogers if (first && !zero_count) { 5638dc26b6fSIan Rogers /* Line was erroneous just '0x'. */ 5648dc26b6fSIan Rogers goto error; 5658dc26b6fSIan Rogers } 5668dc26b6fSIan Rogers /* 5678dc26b6fSIan Rogers * Line was 0x0..0, the sentinel for binutils. Remove 5688dc26b6fSIan Rogers * the function and filename lines. 5698dc26b6fSIan Rogers */ 5708dc26b6fSIan Rogers zfree(&line); 5718dc26b6fSIan Rogers do { 5728dc26b6fSIan Rogers ch = io__get_char(io); 5738dc26b6fSIan Rogers } while (ch > 0 && ch != '\n'); 5748dc26b6fSIan Rogers do { 5758dc26b6fSIan Rogers ch = io__get_char(io); 5768dc26b6fSIan Rogers } while (ch > 0 && ch != '\n'); 5778dc26b6fSIan Rogers return 0; 5788dc26b6fSIan Rogers } 5798dc26b6fSIan Rogers } 580*e90208e9SIan Rogers } 581*e90208e9SIan Rogers /* Read the second function name line (if inline data then this is the first line). */ 582*e90208e9SIan Rogers if (first && (io__getline(io, &line, &line_len) < 0 || !line_len)) 5838dc26b6fSIan Rogers goto error; 5842c4b9280SIan Rogers 585*e90208e9SIan Rogers pr_debug("%s %s: addr2line read line: %s", __func__, dso_name, line); 586be8ecc57STony Garnock-Jones if (function != NULL) 587be8ecc57STony Garnock-Jones *function = strdup(strim(line)); 588be8ecc57STony Garnock-Jones 589be8ecc57STony Garnock-Jones zfree(&line); 590be8ecc57STony Garnock-Jones line_len = 0; 591be8ecc57STony Garnock-Jones 5928dc26b6fSIan Rogers /* Read the third filename and line number line. */ 593b3801e79SIan Rogers if (io__getline(io, &line, &line_len) < 0 || !line_len) 594be8ecc57STony Garnock-Jones goto error; 595be8ecc57STony Garnock-Jones 596*e90208e9SIan Rogers pr_debug("%s %s: addr2line filename:number : %s", __func__, dso_name, line); 5972c4b9280SIan Rogers if (filename_split(line, line_nr == NULL ? &dummy_line_nr : line_nr) == 0 && 5982c4b9280SIan Rogers style == GNU_BINUTILS) { 599be8ecc57STony Garnock-Jones ret = 0; 600be8ecc57STony Garnock-Jones goto error; 601be8ecc57STony Garnock-Jones } 602be8ecc57STony Garnock-Jones 603be8ecc57STony Garnock-Jones if (filename != NULL) 604be8ecc57STony Garnock-Jones *filename = strdup(line); 605be8ecc57STony Garnock-Jones 606be8ecc57STony Garnock-Jones zfree(&line); 607be8ecc57STony Garnock-Jones line_len = 0; 608be8ecc57STony Garnock-Jones 609be8ecc57STony Garnock-Jones return 1; 610be8ecc57STony Garnock-Jones 611be8ecc57STony Garnock-Jones error: 612be8ecc57STony Garnock-Jones free(line); 613be8ecc57STony Garnock-Jones if (function != NULL) 614be8ecc57STony Garnock-Jones zfree(function); 615be8ecc57STony Garnock-Jones if (filename != NULL) 616be8ecc57STony Garnock-Jones zfree(filename); 617f048d548SNamhyung Kim return ret; 618f048d548SNamhyung Kim } 619454ff00fSAdrian Hunter 620be8ecc57STony Garnock-Jones static int inline_list__append_record(struct dso *dso, 621be8ecc57STony Garnock-Jones struct inline_node *node, 622be8ecc57STony Garnock-Jones struct symbol *sym, 623be8ecc57STony Garnock-Jones const char *function, 624be8ecc57STony Garnock-Jones const char *filename, 625be8ecc57STony Garnock-Jones unsigned int line_nr) 626454ff00fSAdrian Hunter { 627be8ecc57STony Garnock-Jones struct symbol *inline_sym = new_inline_sym(dso, sym, function); 628be8ecc57STony Garnock-Jones 629be8ecc57STony Garnock-Jones return inline_list__append(inline_sym, srcline_from_fileline(filename, line_nr), node); 630454ff00fSAdrian Hunter } 631454ff00fSAdrian Hunter 632be8ecc57STony Garnock-Jones static int addr2line(const char *dso_name, u64 addr, 633be8ecc57STony Garnock-Jones char **file, unsigned int *line_nr, 634be8ecc57STony Garnock-Jones struct dso *dso, 635be8ecc57STony Garnock-Jones bool unwind_inlines, 636be8ecc57STony Garnock-Jones struct inline_node *node, 637be8ecc57STony Garnock-Jones struct symbol *sym __maybe_unused) 638be8ecc57STony Garnock-Jones { 639b3801e79SIan Rogers struct child_process *a2l = dso->a2l; 640be8ecc57STony Garnock-Jones char *record_function = NULL; 641be8ecc57STony Garnock-Jones char *record_filename = NULL; 642be8ecc57STony Garnock-Jones unsigned int record_line_nr = 0; 643be8ecc57STony Garnock-Jones int record_status = -1; 644be8ecc57STony Garnock-Jones int ret = 0; 645be8ecc57STony Garnock-Jones size_t inline_count = 0; 646b3801e79SIan Rogers int len; 647b3801e79SIan Rogers char buf[128]; 648b3801e79SIan Rogers ssize_t written; 649701677b9SIan Rogers struct io io = { .eof = false }; 6502c4b9280SIan Rogers enum a2l_style a2l_style; 651be8ecc57STony Garnock-Jones 652be8ecc57STony Garnock-Jones if (!a2l) { 6533b27222dSNamhyung Kim if (!filename__has_section(dso_name, ".debug_line")) 6543b27222dSNamhyung Kim goto out; 6553b27222dSNamhyung Kim 656*e90208e9SIan Rogers dso->a2l = addr2line_subprocess_init(symbol_conf.addr2line_path, dso_name); 657be8ecc57STony Garnock-Jones a2l = dso->a2l; 658be8ecc57STony Garnock-Jones } 659be8ecc57STony Garnock-Jones 660be8ecc57STony Garnock-Jones if (a2l == NULL) { 661be8ecc57STony Garnock-Jones if (!symbol_conf.disable_add2line_warn) 662be8ecc57STony Garnock-Jones pr_warning("%s %s: addr2line_subprocess_init failed\n", __func__, dso_name); 663be8ecc57STony Garnock-Jones goto out; 664be8ecc57STony Garnock-Jones } 665c7a0023aSIan Rogers a2l_style = addr2line_configure(a2l, dso_name); 666c7a0023aSIan Rogers if (a2l_style == BROKEN) 6672c4b9280SIan Rogers goto out; 668be8ecc57STony Garnock-Jones 669be8ecc57STony Garnock-Jones /* 670*e90208e9SIan Rogers * Send our request and then *deliberately* send something that can't be 671*e90208e9SIan Rogers * interpreted as a valid address to ask addr2line about (namely, 672*e90208e9SIan Rogers * ","). This causes addr2line to first write out the answer to our 673*e90208e9SIan Rogers * request, in an unbounded/unknown number of records, and then to write 674*e90208e9SIan Rogers * out the lines "0x0...0", "??" and "??:0", for GNU binutils, or "," 675*e90208e9SIan Rogers * for llvm-addr2line, so that we can detect when it has finished giving 676*e90208e9SIan Rogers * us anything useful. 677be8ecc57STony Garnock-Jones */ 678b3801e79SIan Rogers len = snprintf(buf, sizeof(buf), "%016"PRIx64"\n,\n", addr); 679b3801e79SIan Rogers written = len > 0 ? write(a2l->in, buf, len) : -1; 680b3801e79SIan Rogers if (written != len) { 681d5e33ce0SNamhyung Kim if (!symbol_conf.disable_add2line_warn) 682be8ecc57STony Garnock-Jones pr_warning("%s %s: could not send request\n", __func__, dso_name); 683be8ecc57STony Garnock-Jones goto out; 684be8ecc57STony Garnock-Jones } 685b3801e79SIan Rogers io__init(&io, a2l->out, buf, sizeof(buf)); 686701677b9SIan Rogers io.timeout_ms = addr2line_timeout_ms; 687*e90208e9SIan Rogers switch (read_addr2line_record(&io, a2l_style, dso_name, addr, /*first=*/true, 6882c4b9280SIan Rogers &record_function, &record_filename, &record_line_nr)) { 689be8ecc57STony Garnock-Jones case -1: 690d5e33ce0SNamhyung Kim if (!symbol_conf.disable_add2line_warn) 691be8ecc57STony Garnock-Jones pr_warning("%s %s: could not read first record\n", __func__, dso_name); 692be8ecc57STony Garnock-Jones goto out; 693be8ecc57STony Garnock-Jones case 0: 694be8ecc57STony Garnock-Jones /* 6958dc26b6fSIan Rogers * The first record was invalid, so return failure, but first 6968dc26b6fSIan Rogers * read another record, since we sent a sentinel ',' for the 697*e90208e9SIan Rogers * sake of detected the last inlined function. Treat this as the 698*e90208e9SIan Rogers * first of a record as the ',' generates a new start with GNU 699*e90208e9SIan Rogers * binutils, also force a non-zero address as we're no longer 700*e90208e9SIan Rogers * reading that record. 701be8ecc57STony Garnock-Jones */ 702*e90208e9SIan Rogers switch (read_addr2line_record(&io, a2l_style, dso_name, 703*e90208e9SIan Rogers /*addr=*/1, /*first=*/true, 704*e90208e9SIan Rogers NULL, NULL, NULL)) { 705be8ecc57STony Garnock-Jones case -1: 706d5e33ce0SNamhyung Kim if (!symbol_conf.disable_add2line_warn) 707*e90208e9SIan Rogers pr_warning("%s %s: could not read sentinel record\n", 708d5e33ce0SNamhyung Kim __func__, dso_name); 709be8ecc57STony Garnock-Jones break; 710be8ecc57STony Garnock-Jones case 0: 711*e90208e9SIan Rogers /* The sentinel as expected. */ 712be8ecc57STony Garnock-Jones break; 713be8ecc57STony Garnock-Jones default: 714d5e33ce0SNamhyung Kim if (!symbol_conf.disable_add2line_warn) 715be8ecc57STony Garnock-Jones pr_warning("%s %s: unexpected record instead of sentinel", 716be8ecc57STony Garnock-Jones __func__, dso_name); 717be8ecc57STony Garnock-Jones break; 718be8ecc57STony Garnock-Jones } 719be8ecc57STony Garnock-Jones goto out; 720be8ecc57STony Garnock-Jones default: 721*e90208e9SIan Rogers /* First record as expected. */ 722be8ecc57STony Garnock-Jones break; 723be8ecc57STony Garnock-Jones } 724be8ecc57STony Garnock-Jones 725be8ecc57STony Garnock-Jones if (file) { 726be8ecc57STony Garnock-Jones *file = strdup(record_filename); 727be8ecc57STony Garnock-Jones ret = 1; 728be8ecc57STony Garnock-Jones } 729be8ecc57STony Garnock-Jones if (line_nr) 730be8ecc57STony Garnock-Jones *line_nr = record_line_nr; 731be8ecc57STony Garnock-Jones 732be8ecc57STony Garnock-Jones if (unwind_inlines) { 733be8ecc57STony Garnock-Jones if (node && inline_list__append_record(dso, node, sym, 734be8ecc57STony Garnock-Jones record_function, 735be8ecc57STony Garnock-Jones record_filename, 736be8ecc57STony Garnock-Jones record_line_nr)) { 737be8ecc57STony Garnock-Jones ret = 0; 738be8ecc57STony Garnock-Jones goto out; 739be8ecc57STony Garnock-Jones } 740be8ecc57STony Garnock-Jones } 741be8ecc57STony Garnock-Jones 742*e90208e9SIan Rogers /* 743*e90208e9SIan Rogers * We have to read the records even if we don't care about the inline 744*e90208e9SIan Rogers * info. This isn't the first record and force the address to non-zero 745*e90208e9SIan Rogers * as we're reading records beyond the first. 746*e90208e9SIan Rogers */ 747b3801e79SIan Rogers while ((record_status = read_addr2line_record(&io, 7482c4b9280SIan Rogers a2l_style, 749*e90208e9SIan Rogers dso_name, 750*e90208e9SIan Rogers /*addr=*/1, 751*e90208e9SIan Rogers /*first=*/false, 752be8ecc57STony Garnock-Jones &record_function, 753be8ecc57STony Garnock-Jones &record_filename, 754be8ecc57STony Garnock-Jones &record_line_nr)) == 1) { 755be8ecc57STony Garnock-Jones if (unwind_inlines && node && inline_count++ < MAX_INLINE_NEST) { 756be8ecc57STony Garnock-Jones if (inline_list__append_record(dso, node, sym, 757be8ecc57STony Garnock-Jones record_function, 758be8ecc57STony Garnock-Jones record_filename, 759be8ecc57STony Garnock-Jones record_line_nr)) { 760be8ecc57STony Garnock-Jones ret = 0; 761be8ecc57STony Garnock-Jones goto out; 762be8ecc57STony Garnock-Jones } 763be8ecc57STony Garnock-Jones ret = 1; /* found at least one inline frame */ 764be8ecc57STony Garnock-Jones } 765be8ecc57STony Garnock-Jones } 766be8ecc57STony Garnock-Jones 767be8ecc57STony Garnock-Jones out: 768be8ecc57STony Garnock-Jones free(record_function); 769be8ecc57STony Garnock-Jones free(record_filename); 770701677b9SIan Rogers if (io.eof) { 771701677b9SIan Rogers dso->a2l = NULL; 772701677b9SIan Rogers addr2line_subprocess_cleanup(a2l); 773701677b9SIan Rogers } 774be8ecc57STony Garnock-Jones return ret; 775be8ecc57STony Garnock-Jones } 776be8ecc57STony Garnock-Jones 777be8ecc57STony Garnock-Jones void dso__free_a2l(struct dso *dso) 778be8ecc57STony Garnock-Jones { 779b3801e79SIan Rogers struct child_process *a2l = dso->a2l; 780be8ecc57STony Garnock-Jones 781be8ecc57STony Garnock-Jones if (!a2l) 782be8ecc57STony Garnock-Jones return; 783be8ecc57STony Garnock-Jones 784be8ecc57STony Garnock-Jones addr2line_subprocess_cleanup(a2l); 785be8ecc57STony Garnock-Jones 786be8ecc57STony Garnock-Jones dso->a2l = NULL; 787be8ecc57STony Garnock-Jones } 788be8ecc57STony Garnock-Jones 789be8ecc57STony Garnock-Jones #endif /* HAVE_LIBBFD_SUPPORT */ 790be8ecc57STony Garnock-Jones 791a64489c5SJin Yao static struct inline_node *addr2inlines(const char *dso_name, u64 addr, 792be8ecc57STony Garnock-Jones struct dso *dso, struct symbol *sym) 793a64489c5SJin Yao { 794a64489c5SJin Yao struct inline_node *node; 795a64489c5SJin Yao 796a64489c5SJin Yao node = zalloc(sizeof(*node)); 797a64489c5SJin Yao if (node == NULL) { 798a64489c5SJin Yao perror("not enough memory for the inline node"); 799be8ecc57STony Garnock-Jones return NULL; 800a64489c5SJin Yao } 801a64489c5SJin Yao 802a64489c5SJin Yao INIT_LIST_HEAD(&node->val); 803a64489c5SJin Yao node->addr = addr; 804a64489c5SJin Yao 805be8ecc57STony Garnock-Jones addr2line(dso_name, addr, NULL, NULL, dso, true, node, sym); 806a64489c5SJin Yao return node; 807a64489c5SJin Yao } 808a64489c5SJin Yao 809906049c8SAdrian Hunter /* 810906049c8SAdrian Hunter * Number of addr2line failures (without success) before disabling it for that 811906049c8SAdrian Hunter * dso. 812906049c8SAdrian Hunter */ 813906049c8SAdrian Hunter #define A2L_FAIL_LIMIT 123 814906049c8SAdrian Hunter 8152f84b42bSAndi Kleen char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym, 816935f5a9dSJin Yao bool show_sym, bool show_addr, bool unwind_inlines, 817935f5a9dSJin Yao u64 ip) 818f048d548SNamhyung Kim { 819a949fffbSDavid Ahern char *file = NULL; 820a949fffbSDavid Ahern unsigned line = 0; 8212cc9d0efSNamhyung Kim char *srcline; 822bf4414aeSArnaldo Carvalho de Melo const char *dso_name; 823f048d548SNamhyung Kim 8242cc9d0efSNamhyung Kim if (!dso->has_srcline) 82523f0981bSAndi Kleen goto out; 8262cc9d0efSNamhyung Kim 8275580338dSJin Yao dso_name = dso__name(dso); 8285580338dSJin Yao if (dso_name == NULL) 82958d91a00SNamhyung Kim goto out; 83058d91a00SNamhyung Kim 831fea0cf84SMilian Wolff if (!addr2line(dso_name, addr, &file, &line, dso, 832fea0cf84SMilian Wolff unwind_inlines, NULL, sym)) 83358d91a00SNamhyung Kim goto out; 834f048d548SNamhyung Kim 8352be8832fSMilian Wolff srcline = srcline_from_fileline(file, line); 836906049c8SAdrian Hunter free(file); 8372be8832fSMilian Wolff 8382be8832fSMilian Wolff if (!srcline) 839906049c8SAdrian Hunter goto out; 840906049c8SAdrian Hunter 841906049c8SAdrian Hunter dso->a2l_fails = 0; 842f048d548SNamhyung Kim 843f048d548SNamhyung Kim return srcline; 8442cc9d0efSNamhyung Kim 8452cc9d0efSNamhyung Kim out: 846906049c8SAdrian Hunter if (dso->a2l_fails && ++dso->a2l_fails > A2L_FAIL_LIMIT) { 8472cc9d0efSNamhyung Kim dso->has_srcline = 0; 848454ff00fSAdrian Hunter dso__free_a2l(dso); 849906049c8SAdrian Hunter } 8505dfa210eSMilian Wolff 8515dfa210eSMilian Wolff if (!show_addr) 8525dfa210eSMilian Wolff return (show_sym && sym) ? 853ea335ef3SNamhyung Kim strndup(sym->name, sym->namelen) : SRCLINE_UNKNOWN; 8545dfa210eSMilian Wolff 85585c116a6SAndi Kleen if (sym) { 856ac931f87SWang Nan if (asprintf(&srcline, "%s+%" PRIu64, show_sym ? sym->name : "", 857935f5a9dSJin Yao ip - sym->start) < 0) 85885c116a6SAndi Kleen return SRCLINE_UNKNOWN; 859ac931f87SWang Nan } else if (asprintf(&srcline, "%s[%" PRIx64 "]", dso->short_name, addr) < 0) 8602cc9d0efSNamhyung Kim return SRCLINE_UNKNOWN; 86123f0981bSAndi Kleen return srcline; 862f048d548SNamhyung Kim } 863f048d548SNamhyung Kim 864dd2e18e9SAndi Kleen /* Returns filename and fills in line number in line */ 865dd2e18e9SAndi Kleen char *get_srcline_split(struct dso *dso, u64 addr, unsigned *line) 866dd2e18e9SAndi Kleen { 867dd2e18e9SAndi Kleen char *file = NULL; 868dd2e18e9SAndi Kleen const char *dso_name; 869dd2e18e9SAndi Kleen 870dd2e18e9SAndi Kleen if (!dso->has_srcline) 871dd2e18e9SAndi Kleen goto out; 872dd2e18e9SAndi Kleen 873dd2e18e9SAndi Kleen dso_name = dso__name(dso); 874dd2e18e9SAndi Kleen if (dso_name == NULL) 875dd2e18e9SAndi Kleen goto out; 876dd2e18e9SAndi Kleen 877dd2e18e9SAndi Kleen if (!addr2line(dso_name, addr, &file, line, dso, true, NULL, NULL)) 878dd2e18e9SAndi Kleen goto out; 879dd2e18e9SAndi Kleen 880dd2e18e9SAndi Kleen dso->a2l_fails = 0; 881dd2e18e9SAndi Kleen return file; 882dd2e18e9SAndi Kleen 883dd2e18e9SAndi Kleen out: 884dd2e18e9SAndi Kleen if (dso->a2l_fails && ++dso->a2l_fails > A2L_FAIL_LIMIT) { 885dd2e18e9SAndi Kleen dso->has_srcline = 0; 886dd2e18e9SAndi Kleen dso__free_a2l(dso); 887dd2e18e9SAndi Kleen } 888dd2e18e9SAndi Kleen 889dd2e18e9SAndi Kleen return NULL; 890dd2e18e9SAndi Kleen } 891dd2e18e9SAndi Kleen 892625db36eSIan Rogers void zfree_srcline(char **srcline) 893f048d548SNamhyung Kim { 894625db36eSIan Rogers if (*srcline == NULL) 895625db36eSIan Rogers return; 896625db36eSIan Rogers 897922db21dSArnaldo Carvalho de Melo if (*srcline != SRCLINE_UNKNOWN) 898625db36eSIan Rogers free(*srcline); 899625db36eSIan Rogers 900625db36eSIan Rogers *srcline = NULL; 901f048d548SNamhyung Kim } 9022f84b42bSAndi Kleen 9032f84b42bSAndi Kleen char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym, 904935f5a9dSJin Yao bool show_sym, bool show_addr, u64 ip) 9052f84b42bSAndi Kleen { 906935f5a9dSJin Yao return __get_srcline(dso, addr, sym, show_sym, show_addr, false, ip); 9072f84b42bSAndi Kleen } 908a64489c5SJin Yao 90921ac9d54SMilian Wolff struct srcline_node { 91021ac9d54SMilian Wolff u64 addr; 91121ac9d54SMilian Wolff char *srcline; 91221ac9d54SMilian Wolff struct rb_node rb_node; 91321ac9d54SMilian Wolff }; 91421ac9d54SMilian Wolff 91555ecd631SDavidlohr Bueso void srcline__tree_insert(struct rb_root_cached *tree, u64 addr, char *srcline) 91621ac9d54SMilian Wolff { 91755ecd631SDavidlohr Bueso struct rb_node **p = &tree->rb_root.rb_node; 91821ac9d54SMilian Wolff struct rb_node *parent = NULL; 91921ac9d54SMilian Wolff struct srcline_node *i, *node; 92055ecd631SDavidlohr Bueso bool leftmost = true; 92121ac9d54SMilian Wolff 92221ac9d54SMilian Wolff node = zalloc(sizeof(struct srcline_node)); 92321ac9d54SMilian Wolff if (!node) { 92421ac9d54SMilian Wolff perror("not enough memory for the srcline node"); 92521ac9d54SMilian Wolff return; 92621ac9d54SMilian Wolff } 92721ac9d54SMilian Wolff 92821ac9d54SMilian Wolff node->addr = addr; 92921ac9d54SMilian Wolff node->srcline = srcline; 93021ac9d54SMilian Wolff 93121ac9d54SMilian Wolff while (*p != NULL) { 93221ac9d54SMilian Wolff parent = *p; 93321ac9d54SMilian Wolff i = rb_entry(parent, struct srcline_node, rb_node); 93421ac9d54SMilian Wolff if (addr < i->addr) 93521ac9d54SMilian Wolff p = &(*p)->rb_left; 93655ecd631SDavidlohr Bueso else { 93721ac9d54SMilian Wolff p = &(*p)->rb_right; 93855ecd631SDavidlohr Bueso leftmost = false; 93955ecd631SDavidlohr Bueso } 94021ac9d54SMilian Wolff } 94121ac9d54SMilian Wolff rb_link_node(&node->rb_node, parent, p); 94255ecd631SDavidlohr Bueso rb_insert_color_cached(&node->rb_node, tree, leftmost); 94321ac9d54SMilian Wolff } 94421ac9d54SMilian Wolff 94555ecd631SDavidlohr Bueso char *srcline__tree_find(struct rb_root_cached *tree, u64 addr) 94621ac9d54SMilian Wolff { 94755ecd631SDavidlohr Bueso struct rb_node *n = tree->rb_root.rb_node; 94821ac9d54SMilian Wolff 94921ac9d54SMilian Wolff while (n) { 95021ac9d54SMilian Wolff struct srcline_node *i = rb_entry(n, struct srcline_node, 95121ac9d54SMilian Wolff rb_node); 95221ac9d54SMilian Wolff 95321ac9d54SMilian Wolff if (addr < i->addr) 95421ac9d54SMilian Wolff n = n->rb_left; 95521ac9d54SMilian Wolff else if (addr > i->addr) 95621ac9d54SMilian Wolff n = n->rb_right; 95721ac9d54SMilian Wolff else 95821ac9d54SMilian Wolff return i->srcline; 95921ac9d54SMilian Wolff } 96021ac9d54SMilian Wolff 96121ac9d54SMilian Wolff return NULL; 96221ac9d54SMilian Wolff } 96321ac9d54SMilian Wolff 96455ecd631SDavidlohr Bueso void srcline__tree_delete(struct rb_root_cached *tree) 96521ac9d54SMilian Wolff { 96621ac9d54SMilian Wolff struct srcline_node *pos; 96755ecd631SDavidlohr Bueso struct rb_node *next = rb_first_cached(tree); 96821ac9d54SMilian Wolff 96921ac9d54SMilian Wolff while (next) { 97021ac9d54SMilian Wolff pos = rb_entry(next, struct srcline_node, rb_node); 97121ac9d54SMilian Wolff next = rb_next(&pos->rb_node); 97255ecd631SDavidlohr Bueso rb_erase_cached(&pos->rb_node, tree); 973625db36eSIan Rogers zfree_srcline(&pos->srcline); 97421ac9d54SMilian Wolff zfree(&pos); 97521ac9d54SMilian Wolff } 97621ac9d54SMilian Wolff } 97721ac9d54SMilian Wolff 978fea0cf84SMilian Wolff struct inline_node *dso__parse_addr_inlines(struct dso *dso, u64 addr, 979fea0cf84SMilian Wolff struct symbol *sym) 980a64489c5SJin Yao { 981a64489c5SJin Yao const char *dso_name; 982a64489c5SJin Yao 983a64489c5SJin Yao dso_name = dso__name(dso); 984a64489c5SJin Yao if (dso_name == NULL) 985a64489c5SJin Yao return NULL; 986a64489c5SJin Yao 987fea0cf84SMilian Wolff return addr2inlines(dso_name, addr, dso, sym); 988a64489c5SJin Yao } 989a64489c5SJin Yao 990a64489c5SJin Yao void inline_node__delete(struct inline_node *node) 991a64489c5SJin Yao { 992a64489c5SJin Yao struct inline_list *ilist, *tmp; 993a64489c5SJin Yao 994a64489c5SJin Yao list_for_each_entry_safe(ilist, tmp, &node->val, list) { 995a64489c5SJin Yao list_del_init(&ilist->list); 996625db36eSIan Rogers zfree_srcline(&ilist->srcline); 997fea0cf84SMilian Wolff /* only the inlined symbols are owned by the list */ 998fea0cf84SMilian Wolff if (ilist->symbol && ilist->symbol->inlined) 999fea0cf84SMilian Wolff symbol__delete(ilist->symbol); 1000a64489c5SJin Yao free(ilist); 1001a64489c5SJin Yao } 1002a64489c5SJin Yao 1003a64489c5SJin Yao free(node); 1004a64489c5SJin Yao } 100511ea2515SMilian Wolff 100655ecd631SDavidlohr Bueso void inlines__tree_insert(struct rb_root_cached *tree, 100755ecd631SDavidlohr Bueso struct inline_node *inlines) 100811ea2515SMilian Wolff { 100955ecd631SDavidlohr Bueso struct rb_node **p = &tree->rb_root.rb_node; 101011ea2515SMilian Wolff struct rb_node *parent = NULL; 101111ea2515SMilian Wolff const u64 addr = inlines->addr; 101211ea2515SMilian Wolff struct inline_node *i; 101355ecd631SDavidlohr Bueso bool leftmost = true; 101411ea2515SMilian Wolff 101511ea2515SMilian Wolff while (*p != NULL) { 101611ea2515SMilian Wolff parent = *p; 101711ea2515SMilian Wolff i = rb_entry(parent, struct inline_node, rb_node); 101811ea2515SMilian Wolff if (addr < i->addr) 101911ea2515SMilian Wolff p = &(*p)->rb_left; 102055ecd631SDavidlohr Bueso else { 102111ea2515SMilian Wolff p = &(*p)->rb_right; 102255ecd631SDavidlohr Bueso leftmost = false; 102355ecd631SDavidlohr Bueso } 102411ea2515SMilian Wolff } 102511ea2515SMilian Wolff rb_link_node(&inlines->rb_node, parent, p); 102655ecd631SDavidlohr Bueso rb_insert_color_cached(&inlines->rb_node, tree, leftmost); 102711ea2515SMilian Wolff } 102811ea2515SMilian Wolff 102955ecd631SDavidlohr Bueso struct inline_node *inlines__tree_find(struct rb_root_cached *tree, u64 addr) 103011ea2515SMilian Wolff { 103155ecd631SDavidlohr Bueso struct rb_node *n = tree->rb_root.rb_node; 103211ea2515SMilian Wolff 103311ea2515SMilian Wolff while (n) { 103411ea2515SMilian Wolff struct inline_node *i = rb_entry(n, struct inline_node, 103511ea2515SMilian Wolff rb_node); 103611ea2515SMilian Wolff 103711ea2515SMilian Wolff if (addr < i->addr) 103811ea2515SMilian Wolff n = n->rb_left; 103911ea2515SMilian Wolff else if (addr > i->addr) 104011ea2515SMilian Wolff n = n->rb_right; 104111ea2515SMilian Wolff else 104211ea2515SMilian Wolff return i; 104311ea2515SMilian Wolff } 104411ea2515SMilian Wolff 104511ea2515SMilian Wolff return NULL; 104611ea2515SMilian Wolff } 104711ea2515SMilian Wolff 104855ecd631SDavidlohr Bueso void inlines__tree_delete(struct rb_root_cached *tree) 104911ea2515SMilian Wolff { 105011ea2515SMilian Wolff struct inline_node *pos; 105155ecd631SDavidlohr Bueso struct rb_node *next = rb_first_cached(tree); 105211ea2515SMilian Wolff 105311ea2515SMilian Wolff while (next) { 105411ea2515SMilian Wolff pos = rb_entry(next, struct inline_node, rb_node); 105511ea2515SMilian Wolff next = rb_next(&pos->rb_node); 105655ecd631SDavidlohr Bueso rb_erase_cached(&pos->rb_node, tree); 105711ea2515SMilian Wolff inline_node__delete(pos); 105811ea2515SMilian Wolff } 105911ea2515SMilian Wolff } 1060