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 30ee756ef7SIan Rogers static const char *srcline_dso_name(struct dso *dso) 315580338dSJin Yao { 325580338dSJin Yao const char *dso_name; 335580338dSJin Yao 34ee756ef7SIan Rogers if (dso__symsrc_filename(dso)) 35ee756ef7SIan Rogers dso_name = dso__symsrc_filename(dso); 365580338dSJin Yao else 37ee756ef7SIan Rogers dso_name = dso__long_name(dso); 385580338dSJin Yao 395580338dSJin Yao if (dso_name[0] == '[') 405580338dSJin Yao return NULL; 415580338dSJin Yao 42b9241f15SAthira Rajeev if (is_perf_pid_map_name(dso_name)) 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 { 291*1553419cSIan Rogers struct a2l_data *a2l = dso__a2l(dso); 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; 307*1553419cSIan Rogers struct a2l_data *a2l = dso__a2l(dso); 3082f48fcd8SRoberto Vitillo 309454ff00fSAdrian Hunter if (!a2l) { 310*1553419cSIan Rogers a2l = addr2line_init(dso_name); 311*1553419cSIan Rogers dso__set_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 { 363*1553419cSIan Rogers struct a2l_data *a2l = dso__a2l(dso); 364454ff00fSAdrian Hunter 365454ff00fSAdrian Hunter if (!a2l) 366454ff00fSAdrian Hunter return; 367454ff00fSAdrian Hunter 368454ff00fSAdrian Hunter addr2line_cleanup(a2l); 369454ff00fSAdrian Hunter 370*1553419cSIan Rogers dso__set_a2l(dso, 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; 402c7ba9d18SIan Rogers close(a2l->in); 403c7ba9d18SIan 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 { 641ee756ef7SIan Rogers struct child_process *a2l = dso__a2l(dso); 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 658ee756ef7SIan Rogers dso__set_a2l(dso, 659ee756ef7SIan Rogers addr2line_subprocess_init(symbol_conf.addr2line_path, dso_name)); 660ee756ef7SIan Rogers a2l = dso__a2l(dso); 661be8ecc57STony Garnock-Jones } 662be8ecc57STony Garnock-Jones 663be8ecc57STony Garnock-Jones if (a2l == NULL) { 664be8ecc57STony Garnock-Jones if (!symbol_conf.disable_add2line_warn) 665be8ecc57STony Garnock-Jones pr_warning("%s %s: addr2line_subprocess_init failed\n", __func__, dso_name); 666be8ecc57STony Garnock-Jones goto out; 667be8ecc57STony Garnock-Jones } 668c7a0023aSIan Rogers a2l_style = addr2line_configure(a2l, dso_name); 669c7a0023aSIan Rogers if (a2l_style == BROKEN) 6702c4b9280SIan Rogers goto out; 671be8ecc57STony Garnock-Jones 672be8ecc57STony Garnock-Jones /* 673e90208e9SIan Rogers * Send our request and then *deliberately* send something that can't be 674e90208e9SIan Rogers * interpreted as a valid address to ask addr2line about (namely, 675e90208e9SIan Rogers * ","). This causes addr2line to first write out the answer to our 676e90208e9SIan Rogers * request, in an unbounded/unknown number of records, and then to write 677e90208e9SIan Rogers * out the lines "0x0...0", "??" and "??:0", for GNU binutils, or "," 678e90208e9SIan Rogers * for llvm-addr2line, so that we can detect when it has finished giving 679e90208e9SIan Rogers * us anything useful. 680be8ecc57STony Garnock-Jones */ 681b3801e79SIan Rogers len = snprintf(buf, sizeof(buf), "%016"PRIx64"\n,\n", addr); 682b3801e79SIan Rogers written = len > 0 ? write(a2l->in, buf, len) : -1; 683b3801e79SIan Rogers if (written != len) { 684d5e33ce0SNamhyung Kim if (!symbol_conf.disable_add2line_warn) 685be8ecc57STony Garnock-Jones pr_warning("%s %s: could not send request\n", __func__, dso_name); 686be8ecc57STony Garnock-Jones goto out; 687be8ecc57STony Garnock-Jones } 688b3801e79SIan Rogers io__init(&io, a2l->out, buf, sizeof(buf)); 689701677b9SIan Rogers io.timeout_ms = addr2line_timeout_ms; 690e90208e9SIan Rogers switch (read_addr2line_record(&io, a2l_style, dso_name, addr, /*first=*/true, 6912c4b9280SIan Rogers &record_function, &record_filename, &record_line_nr)) { 692be8ecc57STony Garnock-Jones case -1: 693d5e33ce0SNamhyung Kim if (!symbol_conf.disable_add2line_warn) 694be8ecc57STony Garnock-Jones pr_warning("%s %s: could not read first record\n", __func__, dso_name); 695be8ecc57STony Garnock-Jones goto out; 696be8ecc57STony Garnock-Jones case 0: 697be8ecc57STony Garnock-Jones /* 6988dc26b6fSIan Rogers * The first record was invalid, so return failure, but first 6998dc26b6fSIan Rogers * read another record, since we sent a sentinel ',' for the 700e90208e9SIan Rogers * sake of detected the last inlined function. Treat this as the 701e90208e9SIan Rogers * first of a record as the ',' generates a new start with GNU 702e90208e9SIan Rogers * binutils, also force a non-zero address as we're no longer 703e90208e9SIan Rogers * reading that record. 704be8ecc57STony Garnock-Jones */ 705e90208e9SIan Rogers switch (read_addr2line_record(&io, a2l_style, dso_name, 706e90208e9SIan Rogers /*addr=*/1, /*first=*/true, 707e90208e9SIan Rogers NULL, NULL, NULL)) { 708be8ecc57STony Garnock-Jones case -1: 709d5e33ce0SNamhyung Kim if (!symbol_conf.disable_add2line_warn) 710e90208e9SIan Rogers pr_warning("%s %s: could not read sentinel record\n", 711d5e33ce0SNamhyung Kim __func__, dso_name); 712be8ecc57STony Garnock-Jones break; 713be8ecc57STony Garnock-Jones case 0: 714e90208e9SIan Rogers /* The sentinel as expected. */ 715be8ecc57STony Garnock-Jones break; 716be8ecc57STony Garnock-Jones default: 717d5e33ce0SNamhyung Kim if (!symbol_conf.disable_add2line_warn) 718be8ecc57STony Garnock-Jones pr_warning("%s %s: unexpected record instead of sentinel", 719be8ecc57STony Garnock-Jones __func__, dso_name); 720be8ecc57STony Garnock-Jones break; 721be8ecc57STony Garnock-Jones } 722be8ecc57STony Garnock-Jones goto out; 723be8ecc57STony Garnock-Jones default: 724e90208e9SIan Rogers /* First record as expected. */ 725be8ecc57STony Garnock-Jones break; 726be8ecc57STony Garnock-Jones } 727be8ecc57STony Garnock-Jones 728be8ecc57STony Garnock-Jones if (file) { 729be8ecc57STony Garnock-Jones *file = strdup(record_filename); 730be8ecc57STony Garnock-Jones ret = 1; 731be8ecc57STony Garnock-Jones } 732be8ecc57STony Garnock-Jones if (line_nr) 733be8ecc57STony Garnock-Jones *line_nr = record_line_nr; 734be8ecc57STony Garnock-Jones 735be8ecc57STony Garnock-Jones if (unwind_inlines) { 736be8ecc57STony Garnock-Jones if (node && inline_list__append_record(dso, node, sym, 737be8ecc57STony Garnock-Jones record_function, 738be8ecc57STony Garnock-Jones record_filename, 739be8ecc57STony Garnock-Jones record_line_nr)) { 740be8ecc57STony Garnock-Jones ret = 0; 741be8ecc57STony Garnock-Jones goto out; 742be8ecc57STony Garnock-Jones } 743be8ecc57STony Garnock-Jones } 744be8ecc57STony Garnock-Jones 745e90208e9SIan Rogers /* 746e90208e9SIan Rogers * We have to read the records even if we don't care about the inline 747e90208e9SIan Rogers * info. This isn't the first record and force the address to non-zero 748e90208e9SIan Rogers * as we're reading records beyond the first. 749e90208e9SIan Rogers */ 750b3801e79SIan Rogers while ((record_status = read_addr2line_record(&io, 7512c4b9280SIan Rogers a2l_style, 752e90208e9SIan Rogers dso_name, 753e90208e9SIan Rogers /*addr=*/1, 754e90208e9SIan Rogers /*first=*/false, 755be8ecc57STony Garnock-Jones &record_function, 756be8ecc57STony Garnock-Jones &record_filename, 757be8ecc57STony Garnock-Jones &record_line_nr)) == 1) { 758be8ecc57STony Garnock-Jones if (unwind_inlines && node && inline_count++ < MAX_INLINE_NEST) { 759be8ecc57STony Garnock-Jones if (inline_list__append_record(dso, node, sym, 760be8ecc57STony Garnock-Jones record_function, 761be8ecc57STony Garnock-Jones record_filename, 762be8ecc57STony Garnock-Jones record_line_nr)) { 763be8ecc57STony Garnock-Jones ret = 0; 764be8ecc57STony Garnock-Jones goto out; 765be8ecc57STony Garnock-Jones } 766be8ecc57STony Garnock-Jones ret = 1; /* found at least one inline frame */ 767be8ecc57STony Garnock-Jones } 768be8ecc57STony Garnock-Jones } 769be8ecc57STony Garnock-Jones 770be8ecc57STony Garnock-Jones out: 771be8ecc57STony Garnock-Jones free(record_function); 772be8ecc57STony Garnock-Jones free(record_filename); 773701677b9SIan Rogers if (io.eof) { 774ee756ef7SIan Rogers dso__set_a2l(dso, NULL); 775701677b9SIan Rogers addr2line_subprocess_cleanup(a2l); 776701677b9SIan Rogers } 777be8ecc57STony Garnock-Jones return ret; 778be8ecc57STony Garnock-Jones } 779be8ecc57STony Garnock-Jones 780be8ecc57STony Garnock-Jones void dso__free_a2l(struct dso *dso) 781be8ecc57STony Garnock-Jones { 782ee756ef7SIan Rogers struct child_process *a2l = dso__a2l(dso); 783be8ecc57STony Garnock-Jones 784be8ecc57STony Garnock-Jones if (!a2l) 785be8ecc57STony Garnock-Jones return; 786be8ecc57STony Garnock-Jones 787be8ecc57STony Garnock-Jones addr2line_subprocess_cleanup(a2l); 788be8ecc57STony Garnock-Jones 789ee756ef7SIan Rogers dso__set_a2l(dso, NULL); 790be8ecc57STony Garnock-Jones } 791be8ecc57STony Garnock-Jones 792be8ecc57STony Garnock-Jones #endif /* HAVE_LIBBFD_SUPPORT */ 793be8ecc57STony Garnock-Jones 794a64489c5SJin Yao static struct inline_node *addr2inlines(const char *dso_name, u64 addr, 795be8ecc57STony Garnock-Jones struct dso *dso, struct symbol *sym) 796a64489c5SJin Yao { 797a64489c5SJin Yao struct inline_node *node; 798a64489c5SJin Yao 799a64489c5SJin Yao node = zalloc(sizeof(*node)); 800a64489c5SJin Yao if (node == NULL) { 801a64489c5SJin Yao perror("not enough memory for the inline node"); 802be8ecc57STony Garnock-Jones return NULL; 803a64489c5SJin Yao } 804a64489c5SJin Yao 805a64489c5SJin Yao INIT_LIST_HEAD(&node->val); 806a64489c5SJin Yao node->addr = addr; 807a64489c5SJin Yao 808be8ecc57STony Garnock-Jones addr2line(dso_name, addr, NULL, NULL, dso, true, node, sym); 809a64489c5SJin Yao return node; 810a64489c5SJin Yao } 811a64489c5SJin Yao 812906049c8SAdrian Hunter /* 813906049c8SAdrian Hunter * Number of addr2line failures (without success) before disabling it for that 814906049c8SAdrian Hunter * dso. 815906049c8SAdrian Hunter */ 816906049c8SAdrian Hunter #define A2L_FAIL_LIMIT 123 817906049c8SAdrian Hunter 8182f84b42bSAndi Kleen char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym, 819935f5a9dSJin Yao bool show_sym, bool show_addr, bool unwind_inlines, 820935f5a9dSJin Yao u64 ip) 821f048d548SNamhyung Kim { 822a949fffbSDavid Ahern char *file = NULL; 823a949fffbSDavid Ahern unsigned line = 0; 8242cc9d0efSNamhyung Kim char *srcline; 825bf4414aeSArnaldo Carvalho de Melo const char *dso_name; 826f048d548SNamhyung Kim 827ee756ef7SIan Rogers if (!dso__has_srcline(dso)) 82823f0981bSAndi Kleen goto out; 8292cc9d0efSNamhyung Kim 830ee756ef7SIan Rogers dso_name = srcline_dso_name(dso); 8315580338dSJin Yao if (dso_name == NULL) 832ee756ef7SIan Rogers goto out_err; 83358d91a00SNamhyung Kim 834fea0cf84SMilian Wolff if (!addr2line(dso_name, addr, &file, &line, dso, 835fea0cf84SMilian Wolff unwind_inlines, NULL, sym)) 836ee756ef7SIan Rogers goto out_err; 837f048d548SNamhyung Kim 8382be8832fSMilian Wolff srcline = srcline_from_fileline(file, line); 839906049c8SAdrian Hunter free(file); 8402be8832fSMilian Wolff 8412be8832fSMilian Wolff if (!srcline) 842ee756ef7SIan Rogers goto out_err; 843906049c8SAdrian Hunter 844ee756ef7SIan Rogers dso__set_a2l_fails(dso, 0); 845f048d548SNamhyung Kim 846f048d548SNamhyung Kim return srcline; 8472cc9d0efSNamhyung Kim 848ee756ef7SIan Rogers out_err: 849ee756ef7SIan Rogers dso__set_a2l_fails(dso, dso__a2l_fails(dso) + 1); 850ee756ef7SIan Rogers if (dso__a2l_fails(dso) > A2L_FAIL_LIMIT) { 851ee756ef7SIan Rogers dso__set_has_srcline(dso, false); 852454ff00fSAdrian Hunter dso__free_a2l(dso); 853906049c8SAdrian Hunter } 854ee756ef7SIan Rogers out: 8555dfa210eSMilian Wolff if (!show_addr) 8565dfa210eSMilian Wolff return (show_sym && sym) ? 857ea335ef3SNamhyung Kim strndup(sym->name, sym->namelen) : SRCLINE_UNKNOWN; 8585dfa210eSMilian Wolff 85985c116a6SAndi Kleen if (sym) { 860ac931f87SWang Nan if (asprintf(&srcline, "%s+%" PRIu64, show_sym ? sym->name : "", 861935f5a9dSJin Yao ip - sym->start) < 0) 86285c116a6SAndi Kleen return SRCLINE_UNKNOWN; 863ee756ef7SIan Rogers } else if (asprintf(&srcline, "%s[%" PRIx64 "]", dso__short_name(dso), addr) < 0) 8642cc9d0efSNamhyung Kim return SRCLINE_UNKNOWN; 86523f0981bSAndi Kleen return srcline; 866f048d548SNamhyung Kim } 867f048d548SNamhyung Kim 868dd2e18e9SAndi Kleen /* Returns filename and fills in line number in line */ 869dd2e18e9SAndi Kleen char *get_srcline_split(struct dso *dso, u64 addr, unsigned *line) 870dd2e18e9SAndi Kleen { 871dd2e18e9SAndi Kleen char *file = NULL; 872dd2e18e9SAndi Kleen const char *dso_name; 873dd2e18e9SAndi Kleen 874ee756ef7SIan Rogers if (!dso__has_srcline(dso)) 875ee756ef7SIan Rogers return NULL; 876dd2e18e9SAndi Kleen 877ee756ef7SIan Rogers dso_name = srcline_dso_name(dso); 878dd2e18e9SAndi Kleen if (dso_name == NULL) 879ee756ef7SIan Rogers goto out_err; 880dd2e18e9SAndi Kleen 881dd2e18e9SAndi Kleen if (!addr2line(dso_name, addr, &file, line, dso, true, NULL, NULL)) 882ee756ef7SIan Rogers goto out_err; 883dd2e18e9SAndi Kleen 884ee756ef7SIan Rogers dso__set_a2l_fails(dso, 0); 885dd2e18e9SAndi Kleen return file; 886dd2e18e9SAndi Kleen 887ee756ef7SIan Rogers out_err: 888ee756ef7SIan Rogers dso__set_a2l_fails(dso, dso__a2l_fails(dso) + 1); 889ee756ef7SIan Rogers if (dso__a2l_fails(dso) > A2L_FAIL_LIMIT) { 890ee756ef7SIan Rogers dso__set_has_srcline(dso, false); 891dd2e18e9SAndi Kleen dso__free_a2l(dso); 892dd2e18e9SAndi Kleen } 893dd2e18e9SAndi Kleen 894dd2e18e9SAndi Kleen return NULL; 895dd2e18e9SAndi Kleen } 896dd2e18e9SAndi Kleen 897625db36eSIan Rogers void zfree_srcline(char **srcline) 898f048d548SNamhyung Kim { 899625db36eSIan Rogers if (*srcline == NULL) 900625db36eSIan Rogers return; 901625db36eSIan Rogers 902922db21dSArnaldo Carvalho de Melo if (*srcline != SRCLINE_UNKNOWN) 903625db36eSIan Rogers free(*srcline); 904625db36eSIan Rogers 905625db36eSIan Rogers *srcline = NULL; 906f048d548SNamhyung Kim } 9072f84b42bSAndi Kleen 9082f84b42bSAndi Kleen char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym, 909935f5a9dSJin Yao bool show_sym, bool show_addr, u64 ip) 9102f84b42bSAndi Kleen { 911935f5a9dSJin Yao return __get_srcline(dso, addr, sym, show_sym, show_addr, false, ip); 9122f84b42bSAndi Kleen } 913a64489c5SJin Yao 91421ac9d54SMilian Wolff struct srcline_node { 91521ac9d54SMilian Wolff u64 addr; 91621ac9d54SMilian Wolff char *srcline; 91721ac9d54SMilian Wolff struct rb_node rb_node; 91821ac9d54SMilian Wolff }; 91921ac9d54SMilian Wolff 92055ecd631SDavidlohr Bueso void srcline__tree_insert(struct rb_root_cached *tree, u64 addr, char *srcline) 92121ac9d54SMilian Wolff { 92255ecd631SDavidlohr Bueso struct rb_node **p = &tree->rb_root.rb_node; 92321ac9d54SMilian Wolff struct rb_node *parent = NULL; 92421ac9d54SMilian Wolff struct srcline_node *i, *node; 92555ecd631SDavidlohr Bueso bool leftmost = true; 92621ac9d54SMilian Wolff 92721ac9d54SMilian Wolff node = zalloc(sizeof(struct srcline_node)); 92821ac9d54SMilian Wolff if (!node) { 92921ac9d54SMilian Wolff perror("not enough memory for the srcline node"); 93021ac9d54SMilian Wolff return; 93121ac9d54SMilian Wolff } 93221ac9d54SMilian Wolff 93321ac9d54SMilian Wolff node->addr = addr; 93421ac9d54SMilian Wolff node->srcline = srcline; 93521ac9d54SMilian Wolff 93621ac9d54SMilian Wolff while (*p != NULL) { 93721ac9d54SMilian Wolff parent = *p; 93821ac9d54SMilian Wolff i = rb_entry(parent, struct srcline_node, rb_node); 93921ac9d54SMilian Wolff if (addr < i->addr) 94021ac9d54SMilian Wolff p = &(*p)->rb_left; 94155ecd631SDavidlohr Bueso else { 94221ac9d54SMilian Wolff p = &(*p)->rb_right; 94355ecd631SDavidlohr Bueso leftmost = false; 94455ecd631SDavidlohr Bueso } 94521ac9d54SMilian Wolff } 94621ac9d54SMilian Wolff rb_link_node(&node->rb_node, parent, p); 94755ecd631SDavidlohr Bueso rb_insert_color_cached(&node->rb_node, tree, leftmost); 94821ac9d54SMilian Wolff } 94921ac9d54SMilian Wolff 95055ecd631SDavidlohr Bueso char *srcline__tree_find(struct rb_root_cached *tree, u64 addr) 95121ac9d54SMilian Wolff { 95255ecd631SDavidlohr Bueso struct rb_node *n = tree->rb_root.rb_node; 95321ac9d54SMilian Wolff 95421ac9d54SMilian Wolff while (n) { 95521ac9d54SMilian Wolff struct srcline_node *i = rb_entry(n, struct srcline_node, 95621ac9d54SMilian Wolff rb_node); 95721ac9d54SMilian Wolff 95821ac9d54SMilian Wolff if (addr < i->addr) 95921ac9d54SMilian Wolff n = n->rb_left; 96021ac9d54SMilian Wolff else if (addr > i->addr) 96121ac9d54SMilian Wolff n = n->rb_right; 96221ac9d54SMilian Wolff else 96321ac9d54SMilian Wolff return i->srcline; 96421ac9d54SMilian Wolff } 96521ac9d54SMilian Wolff 96621ac9d54SMilian Wolff return NULL; 96721ac9d54SMilian Wolff } 96821ac9d54SMilian Wolff 96955ecd631SDavidlohr Bueso void srcline__tree_delete(struct rb_root_cached *tree) 97021ac9d54SMilian Wolff { 97121ac9d54SMilian Wolff struct srcline_node *pos; 97255ecd631SDavidlohr Bueso struct rb_node *next = rb_first_cached(tree); 97321ac9d54SMilian Wolff 97421ac9d54SMilian Wolff while (next) { 97521ac9d54SMilian Wolff pos = rb_entry(next, struct srcline_node, rb_node); 97621ac9d54SMilian Wolff next = rb_next(&pos->rb_node); 97755ecd631SDavidlohr Bueso rb_erase_cached(&pos->rb_node, tree); 978625db36eSIan Rogers zfree_srcline(&pos->srcline); 97921ac9d54SMilian Wolff zfree(&pos); 98021ac9d54SMilian Wolff } 98121ac9d54SMilian Wolff } 98221ac9d54SMilian Wolff 983fea0cf84SMilian Wolff struct inline_node *dso__parse_addr_inlines(struct dso *dso, u64 addr, 984fea0cf84SMilian Wolff struct symbol *sym) 985a64489c5SJin Yao { 986a64489c5SJin Yao const char *dso_name; 987a64489c5SJin Yao 988ee756ef7SIan Rogers dso_name = srcline_dso_name(dso); 989a64489c5SJin Yao if (dso_name == NULL) 990a64489c5SJin Yao return NULL; 991a64489c5SJin Yao 992fea0cf84SMilian Wolff return addr2inlines(dso_name, addr, dso, sym); 993a64489c5SJin Yao } 994a64489c5SJin Yao 995a64489c5SJin Yao void inline_node__delete(struct inline_node *node) 996a64489c5SJin Yao { 997a64489c5SJin Yao struct inline_list *ilist, *tmp; 998a64489c5SJin Yao 999a64489c5SJin Yao list_for_each_entry_safe(ilist, tmp, &node->val, list) { 1000a64489c5SJin Yao list_del_init(&ilist->list); 1001625db36eSIan Rogers zfree_srcline(&ilist->srcline); 1002fea0cf84SMilian Wolff /* only the inlined symbols are owned by the list */ 1003fea0cf84SMilian Wolff if (ilist->symbol && ilist->symbol->inlined) 1004fea0cf84SMilian Wolff symbol__delete(ilist->symbol); 1005a64489c5SJin Yao free(ilist); 1006a64489c5SJin Yao } 1007a64489c5SJin Yao 1008a64489c5SJin Yao free(node); 1009a64489c5SJin Yao } 101011ea2515SMilian Wolff 101155ecd631SDavidlohr Bueso void inlines__tree_insert(struct rb_root_cached *tree, 101255ecd631SDavidlohr Bueso struct inline_node *inlines) 101311ea2515SMilian Wolff { 101455ecd631SDavidlohr Bueso struct rb_node **p = &tree->rb_root.rb_node; 101511ea2515SMilian Wolff struct rb_node *parent = NULL; 101611ea2515SMilian Wolff const u64 addr = inlines->addr; 101711ea2515SMilian Wolff struct inline_node *i; 101855ecd631SDavidlohr Bueso bool leftmost = true; 101911ea2515SMilian Wolff 102011ea2515SMilian Wolff while (*p != NULL) { 102111ea2515SMilian Wolff parent = *p; 102211ea2515SMilian Wolff i = rb_entry(parent, struct inline_node, rb_node); 102311ea2515SMilian Wolff if (addr < i->addr) 102411ea2515SMilian Wolff p = &(*p)->rb_left; 102555ecd631SDavidlohr Bueso else { 102611ea2515SMilian Wolff p = &(*p)->rb_right; 102755ecd631SDavidlohr Bueso leftmost = false; 102855ecd631SDavidlohr Bueso } 102911ea2515SMilian Wolff } 103011ea2515SMilian Wolff rb_link_node(&inlines->rb_node, parent, p); 103155ecd631SDavidlohr Bueso rb_insert_color_cached(&inlines->rb_node, tree, leftmost); 103211ea2515SMilian Wolff } 103311ea2515SMilian Wolff 103455ecd631SDavidlohr Bueso struct inline_node *inlines__tree_find(struct rb_root_cached *tree, u64 addr) 103511ea2515SMilian Wolff { 103655ecd631SDavidlohr Bueso struct rb_node *n = tree->rb_root.rb_node; 103711ea2515SMilian Wolff 103811ea2515SMilian Wolff while (n) { 103911ea2515SMilian Wolff struct inline_node *i = rb_entry(n, struct inline_node, 104011ea2515SMilian Wolff rb_node); 104111ea2515SMilian Wolff 104211ea2515SMilian Wolff if (addr < i->addr) 104311ea2515SMilian Wolff n = n->rb_left; 104411ea2515SMilian Wolff else if (addr > i->addr) 104511ea2515SMilian Wolff n = n->rb_right; 104611ea2515SMilian Wolff else 104711ea2515SMilian Wolff return i; 104811ea2515SMilian Wolff } 104911ea2515SMilian Wolff 105011ea2515SMilian Wolff return NULL; 105111ea2515SMilian Wolff } 105211ea2515SMilian Wolff 105355ecd631SDavidlohr Bueso void inlines__tree_delete(struct rb_root_cached *tree) 105411ea2515SMilian Wolff { 105511ea2515SMilian Wolff struct inline_node *pos; 105655ecd631SDavidlohr Bueso struct rb_node *next = rb_first_cached(tree); 105711ea2515SMilian Wolff 105811ea2515SMilian Wolff while (next) { 105911ea2515SMilian Wolff pos = rb_entry(next, struct inline_node, rb_node); 106011ea2515SMilian Wolff next = rb_next(&pos->rb_node); 106155ecd631SDavidlohr Bueso rb_erase_cached(&pos->rb_node, tree); 106211ea2515SMilian Wolff inline_node__delete(pos); 106311ea2515SMilian Wolff } 106411ea2515SMilian Wolff } 1065