18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * dwarf-aux.c : libdw auxiliary interfaces 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <errno.h> 78c2ecf20Sopenharmony_ci#include <inttypes.h> 88c2ecf20Sopenharmony_ci#include <stdbool.h> 98c2ecf20Sopenharmony_ci#include <stdlib.h> 108c2ecf20Sopenharmony_ci#include "debug.h" 118c2ecf20Sopenharmony_ci#include "dwarf-aux.h" 128c2ecf20Sopenharmony_ci#include "strbuf.h" 138c2ecf20Sopenharmony_ci#include "string2.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci/** 168c2ecf20Sopenharmony_ci * cu_find_realpath - Find the realpath of the target file 178c2ecf20Sopenharmony_ci * @cu_die: A DIE(dwarf information entry) of CU(compilation Unit) 188c2ecf20Sopenharmony_ci * @fname: The tail filename of the target file 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * Find the real(long) path of @fname in @cu_die. 218c2ecf20Sopenharmony_ci */ 228c2ecf20Sopenharmony_ciconst char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname) 238c2ecf20Sopenharmony_ci{ 248c2ecf20Sopenharmony_ci Dwarf_Files *files; 258c2ecf20Sopenharmony_ci size_t nfiles, i; 268c2ecf20Sopenharmony_ci const char *src = NULL; 278c2ecf20Sopenharmony_ci int ret; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci if (!fname) 308c2ecf20Sopenharmony_ci return NULL; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci ret = dwarf_getsrcfiles(cu_die, &files, &nfiles); 338c2ecf20Sopenharmony_ci if (ret != 0) 348c2ecf20Sopenharmony_ci return NULL; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci for (i = 0; i < nfiles; i++) { 378c2ecf20Sopenharmony_ci src = dwarf_filesrc(files, i, NULL, NULL); 388c2ecf20Sopenharmony_ci if (strtailcmp(src, fname) == 0) 398c2ecf20Sopenharmony_ci break; 408c2ecf20Sopenharmony_ci } 418c2ecf20Sopenharmony_ci if (i == nfiles) 428c2ecf20Sopenharmony_ci return NULL; 438c2ecf20Sopenharmony_ci return src; 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci/** 478c2ecf20Sopenharmony_ci * cu_get_comp_dir - Get the path of compilation directory 488c2ecf20Sopenharmony_ci * @cu_die: a CU DIE 498c2ecf20Sopenharmony_ci * 508c2ecf20Sopenharmony_ci * Get the path of compilation directory of given @cu_die. 518c2ecf20Sopenharmony_ci * Since this depends on DW_AT_comp_dir, older gcc will not 528c2ecf20Sopenharmony_ci * embedded it. In that case, this returns NULL. 538c2ecf20Sopenharmony_ci */ 548c2ecf20Sopenharmony_ciconst char *cu_get_comp_dir(Dwarf_Die *cu_die) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci Dwarf_Attribute attr; 578c2ecf20Sopenharmony_ci if (dwarf_attr(cu_die, DW_AT_comp_dir, &attr) == NULL) 588c2ecf20Sopenharmony_ci return NULL; 598c2ecf20Sopenharmony_ci return dwarf_formstring(&attr); 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci/* Unlike dwarf_getsrc_die(), cu_getsrc_die() only returns statement line */ 638c2ecf20Sopenharmony_cistatic Dwarf_Line *cu_getsrc_die(Dwarf_Die *cu_die, Dwarf_Addr addr) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci Dwarf_Addr laddr; 668c2ecf20Sopenharmony_ci Dwarf_Lines *lines; 678c2ecf20Sopenharmony_ci Dwarf_Line *line; 688c2ecf20Sopenharmony_ci size_t nlines, l, u, n; 698c2ecf20Sopenharmony_ci bool flag; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci if (dwarf_getsrclines(cu_die, &lines, &nlines) != 0 || 728c2ecf20Sopenharmony_ci nlines == 0) 738c2ecf20Sopenharmony_ci return NULL; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci /* Lines are sorted by address, use binary search */ 768c2ecf20Sopenharmony_ci l = 0; u = nlines - 1; 778c2ecf20Sopenharmony_ci while (l < u) { 788c2ecf20Sopenharmony_ci n = u - (u - l) / 2; 798c2ecf20Sopenharmony_ci line = dwarf_onesrcline(lines, n); 808c2ecf20Sopenharmony_ci if (!line || dwarf_lineaddr(line, &laddr) != 0) 818c2ecf20Sopenharmony_ci return NULL; 828c2ecf20Sopenharmony_ci if (addr < laddr) 838c2ecf20Sopenharmony_ci u = n - 1; 848c2ecf20Sopenharmony_ci else 858c2ecf20Sopenharmony_ci l = n; 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci /* Going backward to find the lowest line */ 888c2ecf20Sopenharmony_ci do { 898c2ecf20Sopenharmony_ci line = dwarf_onesrcline(lines, --l); 908c2ecf20Sopenharmony_ci if (!line || dwarf_lineaddr(line, &laddr) != 0) 918c2ecf20Sopenharmony_ci return NULL; 928c2ecf20Sopenharmony_ci } while (laddr == addr); 938c2ecf20Sopenharmony_ci l++; 948c2ecf20Sopenharmony_ci /* Going foward to find the statement line */ 958c2ecf20Sopenharmony_ci do { 968c2ecf20Sopenharmony_ci line = dwarf_onesrcline(lines, l++); 978c2ecf20Sopenharmony_ci if (!line || dwarf_lineaddr(line, &laddr) != 0 || 988c2ecf20Sopenharmony_ci dwarf_linebeginstatement(line, &flag) != 0) 998c2ecf20Sopenharmony_ci return NULL; 1008c2ecf20Sopenharmony_ci if (laddr > addr) 1018c2ecf20Sopenharmony_ci return NULL; 1028c2ecf20Sopenharmony_ci } while (!flag); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci return line; 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci/** 1088c2ecf20Sopenharmony_ci * cu_find_lineinfo - Get a line number and file name for given address 1098c2ecf20Sopenharmony_ci * @cu_die: a CU DIE 1108c2ecf20Sopenharmony_ci * @addr: An address 1118c2ecf20Sopenharmony_ci * @fname: a pointer which returns the file name string 1128c2ecf20Sopenharmony_ci * @lineno: a pointer which returns the line number 1138c2ecf20Sopenharmony_ci * 1148c2ecf20Sopenharmony_ci * Find a line number and file name for @addr in @cu_die. 1158c2ecf20Sopenharmony_ci */ 1168c2ecf20Sopenharmony_ciint cu_find_lineinfo(Dwarf_Die *cu_die, unsigned long addr, 1178c2ecf20Sopenharmony_ci const char **fname, int *lineno) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci Dwarf_Line *line; 1208c2ecf20Sopenharmony_ci Dwarf_Die die_mem; 1218c2ecf20Sopenharmony_ci Dwarf_Addr faddr; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (die_find_realfunc(cu_die, (Dwarf_Addr)addr, &die_mem) 1248c2ecf20Sopenharmony_ci && die_entrypc(&die_mem, &faddr) == 0 && 1258c2ecf20Sopenharmony_ci faddr == addr) { 1268c2ecf20Sopenharmony_ci *fname = dwarf_decl_file(&die_mem); 1278c2ecf20Sopenharmony_ci dwarf_decl_line(&die_mem, lineno); 1288c2ecf20Sopenharmony_ci goto out; 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci line = cu_getsrc_die(cu_die, (Dwarf_Addr)addr); 1328c2ecf20Sopenharmony_ci if (line && dwarf_lineno(line, lineno) == 0) { 1338c2ecf20Sopenharmony_ci *fname = dwarf_linesrc(line, NULL, NULL); 1348c2ecf20Sopenharmony_ci if (!*fname) 1358c2ecf20Sopenharmony_ci /* line number is useless without filename */ 1368c2ecf20Sopenharmony_ci *lineno = 0; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ciout: 1408c2ecf20Sopenharmony_ci return *lineno ?: -ENOENT; 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic int __die_find_inline_cb(Dwarf_Die *die_mem, void *data); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci/** 1468c2ecf20Sopenharmony_ci * cu_walk_functions_at - Walk on function DIEs at given address 1478c2ecf20Sopenharmony_ci * @cu_die: A CU DIE 1488c2ecf20Sopenharmony_ci * @addr: An address 1498c2ecf20Sopenharmony_ci * @callback: A callback which called with found DIEs 1508c2ecf20Sopenharmony_ci * @data: A user data 1518c2ecf20Sopenharmony_ci * 1528c2ecf20Sopenharmony_ci * Walk on function DIEs at given @addr in @cu_die. Passed DIEs 1538c2ecf20Sopenharmony_ci * should be subprogram or inlined-subroutines. 1548c2ecf20Sopenharmony_ci */ 1558c2ecf20Sopenharmony_ciint cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr, 1568c2ecf20Sopenharmony_ci int (*callback)(Dwarf_Die *, void *), void *data) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci Dwarf_Die die_mem; 1598c2ecf20Sopenharmony_ci Dwarf_Die *sc_die; 1608c2ecf20Sopenharmony_ci int ret = -ENOENT; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci /* Inlined function could be recursive. Trace it until fail */ 1638c2ecf20Sopenharmony_ci for (sc_die = die_find_realfunc(cu_die, addr, &die_mem); 1648c2ecf20Sopenharmony_ci sc_die != NULL; 1658c2ecf20Sopenharmony_ci sc_die = die_find_child(sc_die, __die_find_inline_cb, &addr, 1668c2ecf20Sopenharmony_ci &die_mem)) { 1678c2ecf20Sopenharmony_ci ret = callback(sc_die, data); 1688c2ecf20Sopenharmony_ci if (ret) 1698c2ecf20Sopenharmony_ci break; 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci return ret; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci/** 1778c2ecf20Sopenharmony_ci * die_get_linkage_name - Get the linkage name of the object 1788c2ecf20Sopenharmony_ci * @dw_die: A DIE of the object 1798c2ecf20Sopenharmony_ci * 1808c2ecf20Sopenharmony_ci * Get the linkage name attiribute of given @dw_die. 1818c2ecf20Sopenharmony_ci * For C++ binary, the linkage name will be the mangled symbol. 1828c2ecf20Sopenharmony_ci */ 1838c2ecf20Sopenharmony_ciconst char *die_get_linkage_name(Dwarf_Die *dw_die) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci Dwarf_Attribute attr; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (dwarf_attr_integrate(dw_die, DW_AT_linkage_name, &attr) == NULL) 1888c2ecf20Sopenharmony_ci return NULL; 1898c2ecf20Sopenharmony_ci return dwarf_formstring(&attr); 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci/** 1938c2ecf20Sopenharmony_ci * die_compare_name - Compare diename and tname 1948c2ecf20Sopenharmony_ci * @dw_die: a DIE 1958c2ecf20Sopenharmony_ci * @tname: a string of target name 1968c2ecf20Sopenharmony_ci * 1978c2ecf20Sopenharmony_ci * Compare the name of @dw_die and @tname. Return false if @dw_die has no name. 1988c2ecf20Sopenharmony_ci */ 1998c2ecf20Sopenharmony_cibool die_compare_name(Dwarf_Die *dw_die, const char *tname) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci const char *name; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci name = dwarf_diename(dw_die); 2048c2ecf20Sopenharmony_ci return name ? (strcmp(tname, name) == 0) : false; 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci/** 2088c2ecf20Sopenharmony_ci * die_match_name - Match diename/linkage name and glob 2098c2ecf20Sopenharmony_ci * @dw_die: a DIE 2108c2ecf20Sopenharmony_ci * @glob: a string of target glob pattern 2118c2ecf20Sopenharmony_ci * 2128c2ecf20Sopenharmony_ci * Glob matching the name of @dw_die and @glob. Return false if matching fail. 2138c2ecf20Sopenharmony_ci * This also match linkage name. 2148c2ecf20Sopenharmony_ci */ 2158c2ecf20Sopenharmony_cibool die_match_name(Dwarf_Die *dw_die, const char *glob) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci const char *name; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci name = dwarf_diename(dw_die); 2208c2ecf20Sopenharmony_ci if (name && strglobmatch(name, glob)) 2218c2ecf20Sopenharmony_ci return true; 2228c2ecf20Sopenharmony_ci /* fall back to check linkage name */ 2238c2ecf20Sopenharmony_ci name = die_get_linkage_name(dw_die); 2248c2ecf20Sopenharmony_ci if (name && strglobmatch(name, glob)) 2258c2ecf20Sopenharmony_ci return true; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci return false; 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci/** 2318c2ecf20Sopenharmony_ci * die_get_call_lineno - Get callsite line number of inline-function instance 2328c2ecf20Sopenharmony_ci * @in_die: a DIE of an inlined function instance 2338c2ecf20Sopenharmony_ci * 2348c2ecf20Sopenharmony_ci * Get call-site line number of @in_die. This means from where the inline 2358c2ecf20Sopenharmony_ci * function is called. 2368c2ecf20Sopenharmony_ci */ 2378c2ecf20Sopenharmony_ciint die_get_call_lineno(Dwarf_Die *in_die) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci Dwarf_Attribute attr; 2408c2ecf20Sopenharmony_ci Dwarf_Word ret; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci if (!dwarf_attr(in_die, DW_AT_call_line, &attr)) 2438c2ecf20Sopenharmony_ci return -ENOENT; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci dwarf_formudata(&attr, &ret); 2468c2ecf20Sopenharmony_ci return (int)ret; 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci/** 2508c2ecf20Sopenharmony_ci * die_get_type - Get type DIE 2518c2ecf20Sopenharmony_ci * @vr_die: a DIE of a variable 2528c2ecf20Sopenharmony_ci * @die_mem: where to store a type DIE 2538c2ecf20Sopenharmony_ci * 2548c2ecf20Sopenharmony_ci * Get a DIE of the type of given variable (@vr_die), and store 2558c2ecf20Sopenharmony_ci * it to die_mem. Return NULL if fails to get a type DIE. 2568c2ecf20Sopenharmony_ci */ 2578c2ecf20Sopenharmony_ciDwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci Dwarf_Attribute attr; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (dwarf_attr_integrate(vr_die, DW_AT_type, &attr) && 2628c2ecf20Sopenharmony_ci dwarf_formref_die(&attr, die_mem)) 2638c2ecf20Sopenharmony_ci return die_mem; 2648c2ecf20Sopenharmony_ci else 2658c2ecf20Sopenharmony_ci return NULL; 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci/* Get a type die, but skip qualifiers */ 2698c2ecf20Sopenharmony_cistatic Dwarf_Die *__die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci int tag; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci do { 2748c2ecf20Sopenharmony_ci vr_die = die_get_type(vr_die, die_mem); 2758c2ecf20Sopenharmony_ci if (!vr_die) 2768c2ecf20Sopenharmony_ci break; 2778c2ecf20Sopenharmony_ci tag = dwarf_tag(vr_die); 2788c2ecf20Sopenharmony_ci } while (tag == DW_TAG_const_type || 2798c2ecf20Sopenharmony_ci tag == DW_TAG_restrict_type || 2808c2ecf20Sopenharmony_ci tag == DW_TAG_volatile_type || 2818c2ecf20Sopenharmony_ci tag == DW_TAG_shared_type); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci return vr_die; 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci/** 2878c2ecf20Sopenharmony_ci * die_get_real_type - Get a type die, but skip qualifiers and typedef 2888c2ecf20Sopenharmony_ci * @vr_die: a DIE of a variable 2898c2ecf20Sopenharmony_ci * @die_mem: where to store a type DIE 2908c2ecf20Sopenharmony_ci * 2918c2ecf20Sopenharmony_ci * Get a DIE of the type of given variable (@vr_die), and store 2928c2ecf20Sopenharmony_ci * it to die_mem. Return NULL if fails to get a type DIE. 2938c2ecf20Sopenharmony_ci * If the type is qualifiers (e.g. const) or typedef, this skips it 2948c2ecf20Sopenharmony_ci * and tries to find real type (structure or basic types, e.g. int). 2958c2ecf20Sopenharmony_ci */ 2968c2ecf20Sopenharmony_ciDwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci do { 2998c2ecf20Sopenharmony_ci vr_die = __die_get_real_type(vr_die, die_mem); 3008c2ecf20Sopenharmony_ci } while (vr_die && dwarf_tag(vr_die) == DW_TAG_typedef); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci return vr_die; 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci/* Get attribute and translate it as a udata */ 3068c2ecf20Sopenharmony_cistatic int die_get_attr_udata(Dwarf_Die *tp_die, unsigned int attr_name, 3078c2ecf20Sopenharmony_ci Dwarf_Word *result) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci Dwarf_Attribute attr; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (dwarf_attr_integrate(tp_die, attr_name, &attr) == NULL || 3128c2ecf20Sopenharmony_ci dwarf_formudata(&attr, result) != 0) 3138c2ecf20Sopenharmony_ci return -ENOENT; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci return 0; 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci/** 3198c2ecf20Sopenharmony_ci * die_is_signed_type - Check whether a type DIE is signed or not 3208c2ecf20Sopenharmony_ci * @tp_die: a DIE of a type 3218c2ecf20Sopenharmony_ci * 3228c2ecf20Sopenharmony_ci * Get the encoding of @tp_die and return true if the encoding 3238c2ecf20Sopenharmony_ci * is signed. 3248c2ecf20Sopenharmony_ci */ 3258c2ecf20Sopenharmony_cibool die_is_signed_type(Dwarf_Die *tp_die) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci Dwarf_Word ret; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (die_get_attr_udata(tp_die, DW_AT_encoding, &ret)) 3308c2ecf20Sopenharmony_ci return false; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci return (ret == DW_ATE_signed_char || ret == DW_ATE_signed || 3338c2ecf20Sopenharmony_ci ret == DW_ATE_signed_fixed); 3348c2ecf20Sopenharmony_ci} 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci/** 3378c2ecf20Sopenharmony_ci * die_is_func_def - Ensure that this DIE is a subprogram and definition 3388c2ecf20Sopenharmony_ci * @dw_die: a DIE 3398c2ecf20Sopenharmony_ci * 3408c2ecf20Sopenharmony_ci * Ensure that this DIE is a subprogram and NOT a declaration. This 3418c2ecf20Sopenharmony_ci * returns true if @dw_die is a function definition. 3428c2ecf20Sopenharmony_ci **/ 3438c2ecf20Sopenharmony_cibool die_is_func_def(Dwarf_Die *dw_die) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci Dwarf_Attribute attr; 3468c2ecf20Sopenharmony_ci Dwarf_Addr addr = 0; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci if (dwarf_tag(dw_die) != DW_TAG_subprogram) 3498c2ecf20Sopenharmony_ci return false; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci if (dwarf_attr(dw_die, DW_AT_declaration, &attr)) 3528c2ecf20Sopenharmony_ci return false; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci /* 3558c2ecf20Sopenharmony_ci * DW_AT_declaration can be lost from function declaration 3568c2ecf20Sopenharmony_ci * by gcc's bug #97060. 3578c2ecf20Sopenharmony_ci * So we need to check this subprogram DIE has DW_AT_inline 3588c2ecf20Sopenharmony_ci * or an entry address. 3598c2ecf20Sopenharmony_ci */ 3608c2ecf20Sopenharmony_ci if (!dwarf_attr(dw_die, DW_AT_inline, &attr) && 3618c2ecf20Sopenharmony_ci die_entrypc(dw_die, &addr) < 0) 3628c2ecf20Sopenharmony_ci return false; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci return true; 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci/** 3688c2ecf20Sopenharmony_ci * die_entrypc - Returns entry PC (the lowest address) of a DIE 3698c2ecf20Sopenharmony_ci * @dw_die: a DIE 3708c2ecf20Sopenharmony_ci * @addr: where to store entry PC 3718c2ecf20Sopenharmony_ci * 3728c2ecf20Sopenharmony_ci * Since dwarf_entrypc() does not return entry PC if the DIE has only address 3738c2ecf20Sopenharmony_ci * range, we have to use this to retrieve the lowest address from the address 3748c2ecf20Sopenharmony_ci * range attribute. 3758c2ecf20Sopenharmony_ci */ 3768c2ecf20Sopenharmony_ciint die_entrypc(Dwarf_Die *dw_die, Dwarf_Addr *addr) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci Dwarf_Addr base, end; 3798c2ecf20Sopenharmony_ci Dwarf_Attribute attr; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci if (!addr) 3828c2ecf20Sopenharmony_ci return -EINVAL; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci if (dwarf_entrypc(dw_die, addr) == 0) 3858c2ecf20Sopenharmony_ci return 0; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci /* 3888c2ecf20Sopenharmony_ci * Since the dwarf_ranges() will return 0 if there is no 3898c2ecf20Sopenharmony_ci * DW_AT_ranges attribute, we should check it first. 3908c2ecf20Sopenharmony_ci */ 3918c2ecf20Sopenharmony_ci if (!dwarf_attr(dw_die, DW_AT_ranges, &attr)) 3928c2ecf20Sopenharmony_ci return -ENOENT; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci return dwarf_ranges(dw_die, 0, &base, addr, &end) < 0 ? -ENOENT : 0; 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci/** 3988c2ecf20Sopenharmony_ci * die_is_func_instance - Ensure that this DIE is an instance of a subprogram 3998c2ecf20Sopenharmony_ci * @dw_die: a DIE 4008c2ecf20Sopenharmony_ci * 4018c2ecf20Sopenharmony_ci * Ensure that this DIE is an instance (which has an entry address). 4028c2ecf20Sopenharmony_ci * This returns true if @dw_die is a function instance. If not, the @dw_die 4038c2ecf20Sopenharmony_ci * must be a prototype. You can use die_walk_instances() to find actual 4048c2ecf20Sopenharmony_ci * instances. 4058c2ecf20Sopenharmony_ci **/ 4068c2ecf20Sopenharmony_cibool die_is_func_instance(Dwarf_Die *dw_die) 4078c2ecf20Sopenharmony_ci{ 4088c2ecf20Sopenharmony_ci Dwarf_Addr tmp; 4098c2ecf20Sopenharmony_ci Dwarf_Attribute attr_mem; 4108c2ecf20Sopenharmony_ci int tag = dwarf_tag(dw_die); 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci if (tag != DW_TAG_subprogram && 4138c2ecf20Sopenharmony_ci tag != DW_TAG_inlined_subroutine) 4148c2ecf20Sopenharmony_ci return false; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci return dwarf_entrypc(dw_die, &tmp) == 0 || 4178c2ecf20Sopenharmony_ci dwarf_attr(dw_die, DW_AT_ranges, &attr_mem) != NULL; 4188c2ecf20Sopenharmony_ci} 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci/** 4218c2ecf20Sopenharmony_ci * die_get_data_member_location - Get the data-member offset 4228c2ecf20Sopenharmony_ci * @mb_die: a DIE of a member of a data structure 4238c2ecf20Sopenharmony_ci * @offs: The offset of the member in the data structure 4248c2ecf20Sopenharmony_ci * 4258c2ecf20Sopenharmony_ci * Get the offset of @mb_die in the data structure including @mb_die, and 4268c2ecf20Sopenharmony_ci * stores result offset to @offs. If any error occurs this returns errno. 4278c2ecf20Sopenharmony_ci */ 4288c2ecf20Sopenharmony_ciint die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs) 4298c2ecf20Sopenharmony_ci{ 4308c2ecf20Sopenharmony_ci Dwarf_Attribute attr; 4318c2ecf20Sopenharmony_ci Dwarf_Op *expr; 4328c2ecf20Sopenharmony_ci size_t nexpr; 4338c2ecf20Sopenharmony_ci int ret; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci if (dwarf_attr(mb_die, DW_AT_data_member_location, &attr) == NULL) 4368c2ecf20Sopenharmony_ci return -ENOENT; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci if (dwarf_formudata(&attr, offs) != 0) { 4398c2ecf20Sopenharmony_ci /* DW_AT_data_member_location should be DW_OP_plus_uconst */ 4408c2ecf20Sopenharmony_ci ret = dwarf_getlocation(&attr, &expr, &nexpr); 4418c2ecf20Sopenharmony_ci if (ret < 0 || nexpr == 0) 4428c2ecf20Sopenharmony_ci return -ENOENT; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci if (expr[0].atom != DW_OP_plus_uconst || nexpr != 1) { 4458c2ecf20Sopenharmony_ci pr_debug("Unable to get offset:Unexpected OP %x (%zd)\n", 4468c2ecf20Sopenharmony_ci expr[0].atom, nexpr); 4478c2ecf20Sopenharmony_ci return -ENOTSUP; 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci *offs = (Dwarf_Word)expr[0].number; 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci return 0; 4528c2ecf20Sopenharmony_ci} 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci/* Get the call file index number in CU DIE */ 4558c2ecf20Sopenharmony_cistatic int die_get_call_fileno(Dwarf_Die *in_die) 4568c2ecf20Sopenharmony_ci{ 4578c2ecf20Sopenharmony_ci Dwarf_Word idx; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci if (die_get_attr_udata(in_die, DW_AT_call_file, &idx) == 0) 4608c2ecf20Sopenharmony_ci return (int)idx; 4618c2ecf20Sopenharmony_ci else 4628c2ecf20Sopenharmony_ci return -ENOENT; 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci/* Get the declared file index number in CU DIE */ 4668c2ecf20Sopenharmony_cistatic int die_get_decl_fileno(Dwarf_Die *pdie) 4678c2ecf20Sopenharmony_ci{ 4688c2ecf20Sopenharmony_ci Dwarf_Word idx; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci if (die_get_attr_udata(pdie, DW_AT_decl_file, &idx) == 0) 4718c2ecf20Sopenharmony_ci return (int)idx; 4728c2ecf20Sopenharmony_ci else 4738c2ecf20Sopenharmony_ci return -ENOENT; 4748c2ecf20Sopenharmony_ci} 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci/** 4778c2ecf20Sopenharmony_ci * die_get_call_file - Get callsite file name of inlined function instance 4788c2ecf20Sopenharmony_ci * @in_die: a DIE of an inlined function instance 4798c2ecf20Sopenharmony_ci * 4808c2ecf20Sopenharmony_ci * Get call-site file name of @in_die. This means from which file the inline 4818c2ecf20Sopenharmony_ci * function is called. 4828c2ecf20Sopenharmony_ci */ 4838c2ecf20Sopenharmony_ciconst char *die_get_call_file(Dwarf_Die *in_die) 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci Dwarf_Die cu_die; 4868c2ecf20Sopenharmony_ci Dwarf_Files *files; 4878c2ecf20Sopenharmony_ci int idx; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci idx = die_get_call_fileno(in_die); 4908c2ecf20Sopenharmony_ci if (idx < 0 || !dwarf_diecu(in_die, &cu_die, NULL, NULL) || 4918c2ecf20Sopenharmony_ci dwarf_getsrcfiles(&cu_die, &files, NULL) != 0) 4928c2ecf20Sopenharmony_ci return NULL; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci return dwarf_filesrc(files, idx, NULL, NULL); 4958c2ecf20Sopenharmony_ci} 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci/** 4998c2ecf20Sopenharmony_ci * die_find_child - Generic DIE search function in DIE tree 5008c2ecf20Sopenharmony_ci * @rt_die: a root DIE 5018c2ecf20Sopenharmony_ci * @callback: a callback function 5028c2ecf20Sopenharmony_ci * @data: a user data passed to the callback function 5038c2ecf20Sopenharmony_ci * @die_mem: a buffer for result DIE 5048c2ecf20Sopenharmony_ci * 5058c2ecf20Sopenharmony_ci * Trace DIE tree from @rt_die and call @callback for each child DIE. 5068c2ecf20Sopenharmony_ci * If @callback returns DIE_FIND_CB_END, this stores the DIE into 5078c2ecf20Sopenharmony_ci * @die_mem and returns it. If @callback returns DIE_FIND_CB_CONTINUE, 5088c2ecf20Sopenharmony_ci * this continues to trace the tree. Optionally, @callback can return 5098c2ecf20Sopenharmony_ci * DIE_FIND_CB_CHILD and DIE_FIND_CB_SIBLING, those means trace only 5108c2ecf20Sopenharmony_ci * the children and trace only the siblings respectively. 5118c2ecf20Sopenharmony_ci * Returns NULL if @callback can't find any appropriate DIE. 5128c2ecf20Sopenharmony_ci */ 5138c2ecf20Sopenharmony_ciDwarf_Die *die_find_child(Dwarf_Die *rt_die, 5148c2ecf20Sopenharmony_ci int (*callback)(Dwarf_Die *, void *), 5158c2ecf20Sopenharmony_ci void *data, Dwarf_Die *die_mem) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci Dwarf_Die child_die; 5188c2ecf20Sopenharmony_ci int ret; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci ret = dwarf_child(rt_die, die_mem); 5218c2ecf20Sopenharmony_ci if (ret != 0) 5228c2ecf20Sopenharmony_ci return NULL; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci do { 5258c2ecf20Sopenharmony_ci ret = callback(die_mem, data); 5268c2ecf20Sopenharmony_ci if (ret == DIE_FIND_CB_END) 5278c2ecf20Sopenharmony_ci return die_mem; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci if ((ret & DIE_FIND_CB_CHILD) && 5308c2ecf20Sopenharmony_ci die_find_child(die_mem, callback, data, &child_die)) { 5318c2ecf20Sopenharmony_ci memcpy(die_mem, &child_die, sizeof(Dwarf_Die)); 5328c2ecf20Sopenharmony_ci return die_mem; 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci } while ((ret & DIE_FIND_CB_SIBLING) && 5358c2ecf20Sopenharmony_ci dwarf_siblingof(die_mem, die_mem) == 0); 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci return NULL; 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_cistruct __addr_die_search_param { 5418c2ecf20Sopenharmony_ci Dwarf_Addr addr; 5428c2ecf20Sopenharmony_ci Dwarf_Die *die_mem; 5438c2ecf20Sopenharmony_ci}; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_cistatic int __die_search_func_tail_cb(Dwarf_Die *fn_die, void *data) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci struct __addr_die_search_param *ad = data; 5488c2ecf20Sopenharmony_ci Dwarf_Addr addr = 0; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci if (dwarf_tag(fn_die) == DW_TAG_subprogram && 5518c2ecf20Sopenharmony_ci !dwarf_highpc(fn_die, &addr) && 5528c2ecf20Sopenharmony_ci addr == ad->addr) { 5538c2ecf20Sopenharmony_ci memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die)); 5548c2ecf20Sopenharmony_ci return DWARF_CB_ABORT; 5558c2ecf20Sopenharmony_ci } 5568c2ecf20Sopenharmony_ci return DWARF_CB_OK; 5578c2ecf20Sopenharmony_ci} 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci/** 5608c2ecf20Sopenharmony_ci * die_find_tailfunc - Search for a non-inlined function with tail call at 5618c2ecf20Sopenharmony_ci * given address 5628c2ecf20Sopenharmony_ci * @cu_die: a CU DIE which including @addr 5638c2ecf20Sopenharmony_ci * @addr: target address 5648c2ecf20Sopenharmony_ci * @die_mem: a buffer for result DIE 5658c2ecf20Sopenharmony_ci * 5668c2ecf20Sopenharmony_ci * Search for a non-inlined function DIE with tail call at @addr. Stores the 5678c2ecf20Sopenharmony_ci * DIE to @die_mem and returns it if found. Returns NULL if failed. 5688c2ecf20Sopenharmony_ci */ 5698c2ecf20Sopenharmony_ciDwarf_Die *die_find_tailfunc(Dwarf_Die *cu_die, Dwarf_Addr addr, 5708c2ecf20Sopenharmony_ci Dwarf_Die *die_mem) 5718c2ecf20Sopenharmony_ci{ 5728c2ecf20Sopenharmony_ci struct __addr_die_search_param ad; 5738c2ecf20Sopenharmony_ci ad.addr = addr; 5748c2ecf20Sopenharmony_ci ad.die_mem = die_mem; 5758c2ecf20Sopenharmony_ci /* dwarf_getscopes can't find subprogram. */ 5768c2ecf20Sopenharmony_ci if (!dwarf_getfuncs(cu_die, __die_search_func_tail_cb, &ad, 0)) 5778c2ecf20Sopenharmony_ci return NULL; 5788c2ecf20Sopenharmony_ci else 5798c2ecf20Sopenharmony_ci return die_mem; 5808c2ecf20Sopenharmony_ci} 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci/* die_find callback for non-inlined function search */ 5838c2ecf20Sopenharmony_cistatic int __die_search_func_cb(Dwarf_Die *fn_die, void *data) 5848c2ecf20Sopenharmony_ci{ 5858c2ecf20Sopenharmony_ci struct __addr_die_search_param *ad = data; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci /* 5888c2ecf20Sopenharmony_ci * Since a declaration entry doesn't has given pc, this always returns 5898c2ecf20Sopenharmony_ci * function definition entry. 5908c2ecf20Sopenharmony_ci */ 5918c2ecf20Sopenharmony_ci if (dwarf_tag(fn_die) == DW_TAG_subprogram && 5928c2ecf20Sopenharmony_ci dwarf_haspc(fn_die, ad->addr)) { 5938c2ecf20Sopenharmony_ci memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die)); 5948c2ecf20Sopenharmony_ci return DWARF_CB_ABORT; 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_ci return DWARF_CB_OK; 5978c2ecf20Sopenharmony_ci} 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci/** 6008c2ecf20Sopenharmony_ci * die_find_realfunc - Search a non-inlined function at given address 6018c2ecf20Sopenharmony_ci * @cu_die: a CU DIE which including @addr 6028c2ecf20Sopenharmony_ci * @addr: target address 6038c2ecf20Sopenharmony_ci * @die_mem: a buffer for result DIE 6048c2ecf20Sopenharmony_ci * 6058c2ecf20Sopenharmony_ci * Search a non-inlined function DIE which includes @addr. Stores the 6068c2ecf20Sopenharmony_ci * DIE to @die_mem and returns it if found. Returns NULL if failed. 6078c2ecf20Sopenharmony_ci */ 6088c2ecf20Sopenharmony_ciDwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr, 6098c2ecf20Sopenharmony_ci Dwarf_Die *die_mem) 6108c2ecf20Sopenharmony_ci{ 6118c2ecf20Sopenharmony_ci struct __addr_die_search_param ad; 6128c2ecf20Sopenharmony_ci ad.addr = addr; 6138c2ecf20Sopenharmony_ci ad.die_mem = die_mem; 6148c2ecf20Sopenharmony_ci /* dwarf_getscopes can't find subprogram. */ 6158c2ecf20Sopenharmony_ci if (!dwarf_getfuncs(cu_die, __die_search_func_cb, &ad, 0)) 6168c2ecf20Sopenharmony_ci return NULL; 6178c2ecf20Sopenharmony_ci else 6188c2ecf20Sopenharmony_ci return die_mem; 6198c2ecf20Sopenharmony_ci} 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci/* die_find callback for inline function search */ 6228c2ecf20Sopenharmony_cistatic int __die_find_inline_cb(Dwarf_Die *die_mem, void *data) 6238c2ecf20Sopenharmony_ci{ 6248c2ecf20Sopenharmony_ci Dwarf_Addr *addr = data; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine && 6278c2ecf20Sopenharmony_ci dwarf_haspc(die_mem, *addr)) 6288c2ecf20Sopenharmony_ci return DIE_FIND_CB_END; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci return DIE_FIND_CB_CONTINUE; 6318c2ecf20Sopenharmony_ci} 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci/** 6348c2ecf20Sopenharmony_ci * die_find_top_inlinefunc - Search the top inlined function at given address 6358c2ecf20Sopenharmony_ci * @sp_die: a subprogram DIE which including @addr 6368c2ecf20Sopenharmony_ci * @addr: target address 6378c2ecf20Sopenharmony_ci * @die_mem: a buffer for result DIE 6388c2ecf20Sopenharmony_ci * 6398c2ecf20Sopenharmony_ci * Search an inlined function DIE which includes @addr. Stores the 6408c2ecf20Sopenharmony_ci * DIE to @die_mem and returns it if found. Returns NULL if failed. 6418c2ecf20Sopenharmony_ci * Even if several inlined functions are expanded recursively, this 6428c2ecf20Sopenharmony_ci * doesn't trace it down, and returns the topmost one. 6438c2ecf20Sopenharmony_ci */ 6448c2ecf20Sopenharmony_ciDwarf_Die *die_find_top_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, 6458c2ecf20Sopenharmony_ci Dwarf_Die *die_mem) 6468c2ecf20Sopenharmony_ci{ 6478c2ecf20Sopenharmony_ci return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem); 6488c2ecf20Sopenharmony_ci} 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci/** 6518c2ecf20Sopenharmony_ci * die_find_inlinefunc - Search an inlined function at given address 6528c2ecf20Sopenharmony_ci * @sp_die: a subprogram DIE which including @addr 6538c2ecf20Sopenharmony_ci * @addr: target address 6548c2ecf20Sopenharmony_ci * @die_mem: a buffer for result DIE 6558c2ecf20Sopenharmony_ci * 6568c2ecf20Sopenharmony_ci * Search an inlined function DIE which includes @addr. Stores the 6578c2ecf20Sopenharmony_ci * DIE to @die_mem and returns it if found. Returns NULL if failed. 6588c2ecf20Sopenharmony_ci * If several inlined functions are expanded recursively, this trace 6598c2ecf20Sopenharmony_ci * it down and returns deepest one. 6608c2ecf20Sopenharmony_ci */ 6618c2ecf20Sopenharmony_ciDwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, 6628c2ecf20Sopenharmony_ci Dwarf_Die *die_mem) 6638c2ecf20Sopenharmony_ci{ 6648c2ecf20Sopenharmony_ci Dwarf_Die tmp_die; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci sp_die = die_find_child(sp_die, __die_find_inline_cb, &addr, &tmp_die); 6678c2ecf20Sopenharmony_ci if (!sp_die) 6688c2ecf20Sopenharmony_ci return NULL; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci /* Inlined function could be recursive. Trace it until fail */ 6718c2ecf20Sopenharmony_ci while (sp_die) { 6728c2ecf20Sopenharmony_ci memcpy(die_mem, sp_die, sizeof(Dwarf_Die)); 6738c2ecf20Sopenharmony_ci sp_die = die_find_child(sp_die, __die_find_inline_cb, &addr, 6748c2ecf20Sopenharmony_ci &tmp_die); 6758c2ecf20Sopenharmony_ci } 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci return die_mem; 6788c2ecf20Sopenharmony_ci} 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_cistruct __instance_walk_param { 6818c2ecf20Sopenharmony_ci void *addr; 6828c2ecf20Sopenharmony_ci int (*callback)(Dwarf_Die *, void *); 6838c2ecf20Sopenharmony_ci void *data; 6848c2ecf20Sopenharmony_ci int retval; 6858c2ecf20Sopenharmony_ci}; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_cistatic int __die_walk_instances_cb(Dwarf_Die *inst, void *data) 6888c2ecf20Sopenharmony_ci{ 6898c2ecf20Sopenharmony_ci struct __instance_walk_param *iwp = data; 6908c2ecf20Sopenharmony_ci Dwarf_Attribute attr_mem; 6918c2ecf20Sopenharmony_ci Dwarf_Die origin_mem; 6928c2ecf20Sopenharmony_ci Dwarf_Attribute *attr; 6938c2ecf20Sopenharmony_ci Dwarf_Die *origin; 6948c2ecf20Sopenharmony_ci int tmp; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci if (!die_is_func_instance(inst)) 6978c2ecf20Sopenharmony_ci return DIE_FIND_CB_CONTINUE; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci attr = dwarf_attr(inst, DW_AT_abstract_origin, &attr_mem); 7008c2ecf20Sopenharmony_ci if (attr == NULL) 7018c2ecf20Sopenharmony_ci return DIE_FIND_CB_CONTINUE; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci origin = dwarf_formref_die(attr, &origin_mem); 7048c2ecf20Sopenharmony_ci if (origin == NULL || origin->addr != iwp->addr) 7058c2ecf20Sopenharmony_ci return DIE_FIND_CB_CONTINUE; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci /* Ignore redundant instances */ 7088c2ecf20Sopenharmony_ci if (dwarf_tag(inst) == DW_TAG_inlined_subroutine) { 7098c2ecf20Sopenharmony_ci dwarf_decl_line(origin, &tmp); 7108c2ecf20Sopenharmony_ci if (die_get_call_lineno(inst) == tmp) { 7118c2ecf20Sopenharmony_ci tmp = die_get_decl_fileno(origin); 7128c2ecf20Sopenharmony_ci if (die_get_call_fileno(inst) == tmp) 7138c2ecf20Sopenharmony_ci return DIE_FIND_CB_CONTINUE; 7148c2ecf20Sopenharmony_ci } 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci iwp->retval = iwp->callback(inst, iwp->data); 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci return (iwp->retval) ? DIE_FIND_CB_END : DIE_FIND_CB_CONTINUE; 7208c2ecf20Sopenharmony_ci} 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci/** 7238c2ecf20Sopenharmony_ci * die_walk_instances - Walk on instances of given DIE 7248c2ecf20Sopenharmony_ci * @or_die: an abstract original DIE 7258c2ecf20Sopenharmony_ci * @callback: a callback function which is called with instance DIE 7268c2ecf20Sopenharmony_ci * @data: user data 7278c2ecf20Sopenharmony_ci * 7288c2ecf20Sopenharmony_ci * Walk on the instances of give @in_die. @in_die must be an inlined function 7298c2ecf20Sopenharmony_ci * declartion. This returns the return value of @callback if it returns 7308c2ecf20Sopenharmony_ci * non-zero value, or -ENOENT if there is no instance. 7318c2ecf20Sopenharmony_ci */ 7328c2ecf20Sopenharmony_ciint die_walk_instances(Dwarf_Die *or_die, int (*callback)(Dwarf_Die *, void *), 7338c2ecf20Sopenharmony_ci void *data) 7348c2ecf20Sopenharmony_ci{ 7358c2ecf20Sopenharmony_ci Dwarf_Die cu_die; 7368c2ecf20Sopenharmony_ci Dwarf_Die die_mem; 7378c2ecf20Sopenharmony_ci struct __instance_walk_param iwp = { 7388c2ecf20Sopenharmony_ci .addr = or_die->addr, 7398c2ecf20Sopenharmony_ci .callback = callback, 7408c2ecf20Sopenharmony_ci .data = data, 7418c2ecf20Sopenharmony_ci .retval = -ENOENT, 7428c2ecf20Sopenharmony_ci }; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci if (dwarf_diecu(or_die, &cu_die, NULL, NULL) == NULL) 7458c2ecf20Sopenharmony_ci return -ENOENT; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci die_find_child(&cu_die, __die_walk_instances_cb, &iwp, &die_mem); 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci return iwp.retval; 7508c2ecf20Sopenharmony_ci} 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci/* Line walker internal parameters */ 7538c2ecf20Sopenharmony_cistruct __line_walk_param { 7548c2ecf20Sopenharmony_ci bool recursive; 7558c2ecf20Sopenharmony_ci line_walk_callback_t callback; 7568c2ecf20Sopenharmony_ci void *data; 7578c2ecf20Sopenharmony_ci int retval; 7588c2ecf20Sopenharmony_ci}; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_cistatic int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data) 7618c2ecf20Sopenharmony_ci{ 7628c2ecf20Sopenharmony_ci struct __line_walk_param *lw = data; 7638c2ecf20Sopenharmony_ci Dwarf_Addr addr = 0; 7648c2ecf20Sopenharmony_ci const char *fname; 7658c2ecf20Sopenharmony_ci int lineno; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) { 7688c2ecf20Sopenharmony_ci fname = die_get_call_file(in_die); 7698c2ecf20Sopenharmony_ci lineno = die_get_call_lineno(in_die); 7708c2ecf20Sopenharmony_ci if (fname && lineno > 0 && die_entrypc(in_die, &addr) == 0) { 7718c2ecf20Sopenharmony_ci lw->retval = lw->callback(fname, lineno, addr, lw->data); 7728c2ecf20Sopenharmony_ci if (lw->retval != 0) 7738c2ecf20Sopenharmony_ci return DIE_FIND_CB_END; 7748c2ecf20Sopenharmony_ci } 7758c2ecf20Sopenharmony_ci if (!lw->recursive) 7768c2ecf20Sopenharmony_ci return DIE_FIND_CB_SIBLING; 7778c2ecf20Sopenharmony_ci } 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci if (addr) { 7808c2ecf20Sopenharmony_ci fname = dwarf_decl_file(in_die); 7818c2ecf20Sopenharmony_ci if (fname && dwarf_decl_line(in_die, &lineno) == 0) { 7828c2ecf20Sopenharmony_ci lw->retval = lw->callback(fname, lineno, addr, lw->data); 7838c2ecf20Sopenharmony_ci if (lw->retval != 0) 7848c2ecf20Sopenharmony_ci return DIE_FIND_CB_END; 7858c2ecf20Sopenharmony_ci } 7868c2ecf20Sopenharmony_ci } 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci /* Continue to search nested inlined function call-sites */ 7898c2ecf20Sopenharmony_ci return DIE_FIND_CB_CONTINUE; 7908c2ecf20Sopenharmony_ci} 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci/* Walk on lines of blocks included in given DIE */ 7938c2ecf20Sopenharmony_cistatic int __die_walk_funclines(Dwarf_Die *sp_die, bool recursive, 7948c2ecf20Sopenharmony_ci line_walk_callback_t callback, void *data) 7958c2ecf20Sopenharmony_ci{ 7968c2ecf20Sopenharmony_ci struct __line_walk_param lw = { 7978c2ecf20Sopenharmony_ci .recursive = recursive, 7988c2ecf20Sopenharmony_ci .callback = callback, 7998c2ecf20Sopenharmony_ci .data = data, 8008c2ecf20Sopenharmony_ci .retval = 0, 8018c2ecf20Sopenharmony_ci }; 8028c2ecf20Sopenharmony_ci Dwarf_Die die_mem; 8038c2ecf20Sopenharmony_ci Dwarf_Addr addr; 8048c2ecf20Sopenharmony_ci const char *fname; 8058c2ecf20Sopenharmony_ci int lineno; 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci /* Handle function declaration line */ 8088c2ecf20Sopenharmony_ci fname = dwarf_decl_file(sp_die); 8098c2ecf20Sopenharmony_ci if (fname && dwarf_decl_line(sp_die, &lineno) == 0 && 8108c2ecf20Sopenharmony_ci die_entrypc(sp_die, &addr) == 0) { 8118c2ecf20Sopenharmony_ci lw.retval = callback(fname, lineno, addr, data); 8128c2ecf20Sopenharmony_ci if (lw.retval != 0) 8138c2ecf20Sopenharmony_ci goto done; 8148c2ecf20Sopenharmony_ci } 8158c2ecf20Sopenharmony_ci die_find_child(sp_die, __die_walk_funclines_cb, &lw, &die_mem); 8168c2ecf20Sopenharmony_cidone: 8178c2ecf20Sopenharmony_ci return lw.retval; 8188c2ecf20Sopenharmony_ci} 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_cistatic int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data) 8218c2ecf20Sopenharmony_ci{ 8228c2ecf20Sopenharmony_ci struct __line_walk_param *lw = data; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci /* 8258c2ecf20Sopenharmony_ci * Since inlined function can include another inlined function in 8268c2ecf20Sopenharmony_ci * the same file, we need to walk in it recursively. 8278c2ecf20Sopenharmony_ci */ 8288c2ecf20Sopenharmony_ci lw->retval = __die_walk_funclines(sp_die, true, lw->callback, lw->data); 8298c2ecf20Sopenharmony_ci if (lw->retval != 0) 8308c2ecf20Sopenharmony_ci return DWARF_CB_ABORT; 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci return DWARF_CB_OK; 8338c2ecf20Sopenharmony_ci} 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci/** 8368c2ecf20Sopenharmony_ci * die_walk_lines - Walk on lines inside given DIE 8378c2ecf20Sopenharmony_ci * @rt_die: a root DIE (CU, subprogram or inlined_subroutine) 8388c2ecf20Sopenharmony_ci * @callback: callback routine 8398c2ecf20Sopenharmony_ci * @data: user data 8408c2ecf20Sopenharmony_ci * 8418c2ecf20Sopenharmony_ci * Walk on all lines inside given @rt_die and call @callback on each line. 8428c2ecf20Sopenharmony_ci * If the @rt_die is a function, walk only on the lines inside the function, 8438c2ecf20Sopenharmony_ci * otherwise @rt_die must be a CU DIE. 8448c2ecf20Sopenharmony_ci * Note that this walks not only dwarf line list, but also function entries 8458c2ecf20Sopenharmony_ci * and inline call-site. 8468c2ecf20Sopenharmony_ci */ 8478c2ecf20Sopenharmony_ciint die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data) 8488c2ecf20Sopenharmony_ci{ 8498c2ecf20Sopenharmony_ci Dwarf_Lines *lines; 8508c2ecf20Sopenharmony_ci Dwarf_Line *line; 8518c2ecf20Sopenharmony_ci Dwarf_Addr addr; 8528c2ecf20Sopenharmony_ci const char *fname, *decf = NULL, *inf = NULL; 8538c2ecf20Sopenharmony_ci int lineno, ret = 0; 8548c2ecf20Sopenharmony_ci int decl = 0, inl; 8558c2ecf20Sopenharmony_ci Dwarf_Die die_mem, *cu_die; 8568c2ecf20Sopenharmony_ci size_t nlines, i; 8578c2ecf20Sopenharmony_ci bool flag; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci /* Get the CU die */ 8608c2ecf20Sopenharmony_ci if (dwarf_tag(rt_die) != DW_TAG_compile_unit) { 8618c2ecf20Sopenharmony_ci cu_die = dwarf_diecu(rt_die, &die_mem, NULL, NULL); 8628c2ecf20Sopenharmony_ci dwarf_decl_line(rt_die, &decl); 8638c2ecf20Sopenharmony_ci decf = dwarf_decl_file(rt_die); 8648c2ecf20Sopenharmony_ci } else 8658c2ecf20Sopenharmony_ci cu_die = rt_die; 8668c2ecf20Sopenharmony_ci if (!cu_die) { 8678c2ecf20Sopenharmony_ci pr_debug2("Failed to get CU from given DIE.\n"); 8688c2ecf20Sopenharmony_ci return -EINVAL; 8698c2ecf20Sopenharmony_ci } 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci /* Get lines list in the CU */ 8728c2ecf20Sopenharmony_ci if (dwarf_getsrclines(cu_die, &lines, &nlines) != 0) { 8738c2ecf20Sopenharmony_ci pr_debug2("Failed to get source lines on this CU.\n"); 8748c2ecf20Sopenharmony_ci return -ENOENT; 8758c2ecf20Sopenharmony_ci } 8768c2ecf20Sopenharmony_ci pr_debug2("Get %zd lines from this CU\n", nlines); 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci /* Walk on the lines on lines list */ 8798c2ecf20Sopenharmony_ci for (i = 0; i < nlines; i++) { 8808c2ecf20Sopenharmony_ci line = dwarf_onesrcline(lines, i); 8818c2ecf20Sopenharmony_ci if (line == NULL || 8828c2ecf20Sopenharmony_ci dwarf_lineno(line, &lineno) != 0 || 8838c2ecf20Sopenharmony_ci dwarf_lineaddr(line, &addr) != 0) { 8848c2ecf20Sopenharmony_ci pr_debug2("Failed to get line info. " 8858c2ecf20Sopenharmony_ci "Possible error in debuginfo.\n"); 8868c2ecf20Sopenharmony_ci continue; 8878c2ecf20Sopenharmony_ci } 8888c2ecf20Sopenharmony_ci /* Skip end-of-sequence */ 8898c2ecf20Sopenharmony_ci if (dwarf_lineendsequence(line, &flag) != 0 || flag) 8908c2ecf20Sopenharmony_ci continue; 8918c2ecf20Sopenharmony_ci /* Skip Non statement line-info */ 8928c2ecf20Sopenharmony_ci if (dwarf_linebeginstatement(line, &flag) != 0 || !flag) 8938c2ecf20Sopenharmony_ci continue; 8948c2ecf20Sopenharmony_ci /* Filter lines based on address */ 8958c2ecf20Sopenharmony_ci if (rt_die != cu_die) { 8968c2ecf20Sopenharmony_ci /* 8978c2ecf20Sopenharmony_ci * Address filtering 8988c2ecf20Sopenharmony_ci * The line is included in given function, and 8998c2ecf20Sopenharmony_ci * no inline block includes it. 9008c2ecf20Sopenharmony_ci */ 9018c2ecf20Sopenharmony_ci if (!dwarf_haspc(rt_die, addr)) 9028c2ecf20Sopenharmony_ci continue; 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci if (die_find_inlinefunc(rt_die, addr, &die_mem)) { 9058c2ecf20Sopenharmony_ci /* Call-site check */ 9068c2ecf20Sopenharmony_ci inf = die_get_call_file(&die_mem); 9078c2ecf20Sopenharmony_ci if ((inf && !strcmp(inf, decf)) && 9088c2ecf20Sopenharmony_ci die_get_call_lineno(&die_mem) == lineno) 9098c2ecf20Sopenharmony_ci goto found; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci dwarf_decl_line(&die_mem, &inl); 9128c2ecf20Sopenharmony_ci if (inl != decl || 9138c2ecf20Sopenharmony_ci decf != dwarf_decl_file(&die_mem)) 9148c2ecf20Sopenharmony_ci continue; 9158c2ecf20Sopenharmony_ci } 9168c2ecf20Sopenharmony_ci } 9178c2ecf20Sopenharmony_cifound: 9188c2ecf20Sopenharmony_ci /* Get source line */ 9198c2ecf20Sopenharmony_ci fname = dwarf_linesrc(line, NULL, NULL); 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci ret = callback(fname, lineno, addr, data); 9228c2ecf20Sopenharmony_ci if (ret != 0) 9238c2ecf20Sopenharmony_ci return ret; 9248c2ecf20Sopenharmony_ci } 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci /* 9278c2ecf20Sopenharmony_ci * Dwarf lines doesn't include function declarations and inlined 9288c2ecf20Sopenharmony_ci * subroutines. We have to check functions list or given function. 9298c2ecf20Sopenharmony_ci */ 9308c2ecf20Sopenharmony_ci if (rt_die != cu_die) 9318c2ecf20Sopenharmony_ci /* 9328c2ecf20Sopenharmony_ci * Don't need walk inlined functions recursively, because 9338c2ecf20Sopenharmony_ci * inner inlined functions don't have the lines of the 9348c2ecf20Sopenharmony_ci * specified function. 9358c2ecf20Sopenharmony_ci */ 9368c2ecf20Sopenharmony_ci ret = __die_walk_funclines(rt_die, false, callback, data); 9378c2ecf20Sopenharmony_ci else { 9388c2ecf20Sopenharmony_ci struct __line_walk_param param = { 9398c2ecf20Sopenharmony_ci .callback = callback, 9408c2ecf20Sopenharmony_ci .data = data, 9418c2ecf20Sopenharmony_ci .retval = 0, 9428c2ecf20Sopenharmony_ci }; 9438c2ecf20Sopenharmony_ci dwarf_getfuncs(cu_die, __die_walk_culines_cb, ¶m, 0); 9448c2ecf20Sopenharmony_ci ret = param.retval; 9458c2ecf20Sopenharmony_ci } 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci return ret; 9488c2ecf20Sopenharmony_ci} 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_cistruct __find_variable_param { 9518c2ecf20Sopenharmony_ci const char *name; 9528c2ecf20Sopenharmony_ci Dwarf_Addr addr; 9538c2ecf20Sopenharmony_ci}; 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_cistatic int __die_find_variable_cb(Dwarf_Die *die_mem, void *data) 9568c2ecf20Sopenharmony_ci{ 9578c2ecf20Sopenharmony_ci struct __find_variable_param *fvp = data; 9588c2ecf20Sopenharmony_ci Dwarf_Attribute attr; 9598c2ecf20Sopenharmony_ci int tag; 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci tag = dwarf_tag(die_mem); 9628c2ecf20Sopenharmony_ci if ((tag == DW_TAG_formal_parameter || 9638c2ecf20Sopenharmony_ci tag == DW_TAG_variable) && 9648c2ecf20Sopenharmony_ci die_compare_name(die_mem, fvp->name) && 9658c2ecf20Sopenharmony_ci /* 9668c2ecf20Sopenharmony_ci * Does the DIE have location information or const value 9678c2ecf20Sopenharmony_ci * or external instance? 9688c2ecf20Sopenharmony_ci */ 9698c2ecf20Sopenharmony_ci (dwarf_attr(die_mem, DW_AT_external, &attr) || 9708c2ecf20Sopenharmony_ci dwarf_attr(die_mem, DW_AT_location, &attr) || 9718c2ecf20Sopenharmony_ci dwarf_attr(die_mem, DW_AT_const_value, &attr))) 9728c2ecf20Sopenharmony_ci return DIE_FIND_CB_END; 9738c2ecf20Sopenharmony_ci if (dwarf_haspc(die_mem, fvp->addr)) 9748c2ecf20Sopenharmony_ci return DIE_FIND_CB_CONTINUE; 9758c2ecf20Sopenharmony_ci else 9768c2ecf20Sopenharmony_ci return DIE_FIND_CB_SIBLING; 9778c2ecf20Sopenharmony_ci} 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci/** 9808c2ecf20Sopenharmony_ci * die_find_variable_at - Find a given name variable at given address 9818c2ecf20Sopenharmony_ci * @sp_die: a function DIE 9828c2ecf20Sopenharmony_ci * @name: variable name 9838c2ecf20Sopenharmony_ci * @addr: address 9848c2ecf20Sopenharmony_ci * @die_mem: a buffer for result DIE 9858c2ecf20Sopenharmony_ci * 9868c2ecf20Sopenharmony_ci * Find a variable DIE called @name at @addr in @sp_die. 9878c2ecf20Sopenharmony_ci */ 9888c2ecf20Sopenharmony_ciDwarf_Die *die_find_variable_at(Dwarf_Die *sp_die, const char *name, 9898c2ecf20Sopenharmony_ci Dwarf_Addr addr, Dwarf_Die *die_mem) 9908c2ecf20Sopenharmony_ci{ 9918c2ecf20Sopenharmony_ci struct __find_variable_param fvp = { .name = name, .addr = addr}; 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci return die_find_child(sp_die, __die_find_variable_cb, (void *)&fvp, 9948c2ecf20Sopenharmony_ci die_mem); 9958c2ecf20Sopenharmony_ci} 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_cistatic int __die_find_member_cb(Dwarf_Die *die_mem, void *data) 9988c2ecf20Sopenharmony_ci{ 9998c2ecf20Sopenharmony_ci const char *name = data; 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci if (dwarf_tag(die_mem) == DW_TAG_member) { 10028c2ecf20Sopenharmony_ci if (die_compare_name(die_mem, name)) 10038c2ecf20Sopenharmony_ci return DIE_FIND_CB_END; 10048c2ecf20Sopenharmony_ci else if (!dwarf_diename(die_mem)) { /* Unnamed structure */ 10058c2ecf20Sopenharmony_ci Dwarf_Die type_die, tmp_die; 10068c2ecf20Sopenharmony_ci if (die_get_type(die_mem, &type_die) && 10078c2ecf20Sopenharmony_ci die_find_member(&type_die, name, &tmp_die)) 10088c2ecf20Sopenharmony_ci return DIE_FIND_CB_END; 10098c2ecf20Sopenharmony_ci } 10108c2ecf20Sopenharmony_ci } 10118c2ecf20Sopenharmony_ci return DIE_FIND_CB_SIBLING; 10128c2ecf20Sopenharmony_ci} 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci/** 10158c2ecf20Sopenharmony_ci * die_find_member - Find a given name member in a data structure 10168c2ecf20Sopenharmony_ci * @st_die: a data structure type DIE 10178c2ecf20Sopenharmony_ci * @name: member name 10188c2ecf20Sopenharmony_ci * @die_mem: a buffer for result DIE 10198c2ecf20Sopenharmony_ci * 10208c2ecf20Sopenharmony_ci * Find a member DIE called @name in @st_die. 10218c2ecf20Sopenharmony_ci */ 10228c2ecf20Sopenharmony_ciDwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name, 10238c2ecf20Sopenharmony_ci Dwarf_Die *die_mem) 10248c2ecf20Sopenharmony_ci{ 10258c2ecf20Sopenharmony_ci return die_find_child(st_die, __die_find_member_cb, (void *)name, 10268c2ecf20Sopenharmony_ci die_mem); 10278c2ecf20Sopenharmony_ci} 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci/** 10308c2ecf20Sopenharmony_ci * die_get_typename - Get the name of given variable DIE 10318c2ecf20Sopenharmony_ci * @vr_die: a variable DIE 10328c2ecf20Sopenharmony_ci * @buf: a strbuf for result type name 10338c2ecf20Sopenharmony_ci * 10348c2ecf20Sopenharmony_ci * Get the name of @vr_die and stores it to @buf. Return 0 if succeeded. 10358c2ecf20Sopenharmony_ci * and Return -ENOENT if failed to find type name. 10368c2ecf20Sopenharmony_ci * Note that the result will stores typedef name if possible, and stores 10378c2ecf20Sopenharmony_ci * "*(function_type)" if the type is a function pointer. 10388c2ecf20Sopenharmony_ci */ 10398c2ecf20Sopenharmony_ciint die_get_typename(Dwarf_Die *vr_die, struct strbuf *buf) 10408c2ecf20Sopenharmony_ci{ 10418c2ecf20Sopenharmony_ci Dwarf_Die type; 10428c2ecf20Sopenharmony_ci int tag, ret; 10438c2ecf20Sopenharmony_ci const char *tmp = ""; 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci if (__die_get_real_type(vr_die, &type) == NULL) 10468c2ecf20Sopenharmony_ci return -ENOENT; 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci tag = dwarf_tag(&type); 10498c2ecf20Sopenharmony_ci if (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type) 10508c2ecf20Sopenharmony_ci tmp = "*"; 10518c2ecf20Sopenharmony_ci else if (tag == DW_TAG_subroutine_type) { 10528c2ecf20Sopenharmony_ci /* Function pointer */ 10538c2ecf20Sopenharmony_ci return strbuf_add(buf, "(function_type)", 15); 10548c2ecf20Sopenharmony_ci } else { 10558c2ecf20Sopenharmony_ci if (!dwarf_diename(&type)) 10568c2ecf20Sopenharmony_ci return -ENOENT; 10578c2ecf20Sopenharmony_ci if (tag == DW_TAG_union_type) 10588c2ecf20Sopenharmony_ci tmp = "union "; 10598c2ecf20Sopenharmony_ci else if (tag == DW_TAG_structure_type) 10608c2ecf20Sopenharmony_ci tmp = "struct "; 10618c2ecf20Sopenharmony_ci else if (tag == DW_TAG_enumeration_type) 10628c2ecf20Sopenharmony_ci tmp = "enum "; 10638c2ecf20Sopenharmony_ci /* Write a base name */ 10648c2ecf20Sopenharmony_ci return strbuf_addf(buf, "%s%s", tmp, dwarf_diename(&type)); 10658c2ecf20Sopenharmony_ci } 10668c2ecf20Sopenharmony_ci ret = die_get_typename(&type, buf); 10678c2ecf20Sopenharmony_ci return ret ? ret : strbuf_addstr(buf, tmp); 10688c2ecf20Sopenharmony_ci} 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci/** 10718c2ecf20Sopenharmony_ci * die_get_varname - Get the name and type of given variable DIE 10728c2ecf20Sopenharmony_ci * @vr_die: a variable DIE 10738c2ecf20Sopenharmony_ci * @buf: a strbuf for type and variable name 10748c2ecf20Sopenharmony_ci * 10758c2ecf20Sopenharmony_ci * Get the name and type of @vr_die and stores it in @buf as "type\tname". 10768c2ecf20Sopenharmony_ci */ 10778c2ecf20Sopenharmony_ciint die_get_varname(Dwarf_Die *vr_die, struct strbuf *buf) 10788c2ecf20Sopenharmony_ci{ 10798c2ecf20Sopenharmony_ci int ret; 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci ret = die_get_typename(vr_die, buf); 10828c2ecf20Sopenharmony_ci if (ret < 0) { 10838c2ecf20Sopenharmony_ci pr_debug("Failed to get type, make it unknown.\n"); 10848c2ecf20Sopenharmony_ci ret = strbuf_add(buf, "(unknown_type)", 14); 10858c2ecf20Sopenharmony_ci } 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci return ret < 0 ? ret : strbuf_addf(buf, "\t%s", dwarf_diename(vr_die)); 10888c2ecf20Sopenharmony_ci} 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci#ifdef HAVE_DWARF_GETLOCATIONS_SUPPORT 10918c2ecf20Sopenharmony_ci/** 10928c2ecf20Sopenharmony_ci * die_get_var_innermost_scope - Get innermost scope range of given variable DIE 10938c2ecf20Sopenharmony_ci * @sp_die: a subprogram DIE 10948c2ecf20Sopenharmony_ci * @vr_die: a variable DIE 10958c2ecf20Sopenharmony_ci * @buf: a strbuf for variable byte offset range 10968c2ecf20Sopenharmony_ci * 10978c2ecf20Sopenharmony_ci * Get the innermost scope range of @vr_die and stores it in @buf as 10988c2ecf20Sopenharmony_ci * "@<function_name+[NN-NN,NN-NN]>". 10998c2ecf20Sopenharmony_ci */ 11008c2ecf20Sopenharmony_cistatic int die_get_var_innermost_scope(Dwarf_Die *sp_die, Dwarf_Die *vr_die, 11018c2ecf20Sopenharmony_ci struct strbuf *buf) 11028c2ecf20Sopenharmony_ci{ 11038c2ecf20Sopenharmony_ci Dwarf_Die *scopes; 11048c2ecf20Sopenharmony_ci int count; 11058c2ecf20Sopenharmony_ci size_t offset = 0; 11068c2ecf20Sopenharmony_ci Dwarf_Addr base; 11078c2ecf20Sopenharmony_ci Dwarf_Addr start, end; 11088c2ecf20Sopenharmony_ci Dwarf_Addr entry; 11098c2ecf20Sopenharmony_ci int ret; 11108c2ecf20Sopenharmony_ci bool first = true; 11118c2ecf20Sopenharmony_ci const char *name; 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci ret = die_entrypc(sp_die, &entry); 11148c2ecf20Sopenharmony_ci if (ret) 11158c2ecf20Sopenharmony_ci return ret; 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci name = dwarf_diename(sp_die); 11188c2ecf20Sopenharmony_ci if (!name) 11198c2ecf20Sopenharmony_ci return -ENOENT; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci count = dwarf_getscopes_die(vr_die, &scopes); 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci /* (*SCOPES)[1] is the DIE for the scope containing that scope */ 11248c2ecf20Sopenharmony_ci if (count <= 1) { 11258c2ecf20Sopenharmony_ci ret = -EINVAL; 11268c2ecf20Sopenharmony_ci goto out; 11278c2ecf20Sopenharmony_ci } 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci while ((offset = dwarf_ranges(&scopes[1], offset, &base, 11308c2ecf20Sopenharmony_ci &start, &end)) > 0) { 11318c2ecf20Sopenharmony_ci start -= entry; 11328c2ecf20Sopenharmony_ci end -= entry; 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci if (first) { 11358c2ecf20Sopenharmony_ci ret = strbuf_addf(buf, "@<%s+[%" PRIu64 "-%" PRIu64, 11368c2ecf20Sopenharmony_ci name, start, end); 11378c2ecf20Sopenharmony_ci first = false; 11388c2ecf20Sopenharmony_ci } else { 11398c2ecf20Sopenharmony_ci ret = strbuf_addf(buf, ",%" PRIu64 "-%" PRIu64, 11408c2ecf20Sopenharmony_ci start, end); 11418c2ecf20Sopenharmony_ci } 11428c2ecf20Sopenharmony_ci if (ret < 0) 11438c2ecf20Sopenharmony_ci goto out; 11448c2ecf20Sopenharmony_ci } 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci if (!first) 11478c2ecf20Sopenharmony_ci ret = strbuf_add(buf, "]>", 2); 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ciout: 11508c2ecf20Sopenharmony_ci free(scopes); 11518c2ecf20Sopenharmony_ci return ret; 11528c2ecf20Sopenharmony_ci} 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci/** 11558c2ecf20Sopenharmony_ci * die_get_var_range - Get byte offset range of given variable DIE 11568c2ecf20Sopenharmony_ci * @sp_die: a subprogram DIE 11578c2ecf20Sopenharmony_ci * @vr_die: a variable DIE 11588c2ecf20Sopenharmony_ci * @buf: a strbuf for type and variable name and byte offset range 11598c2ecf20Sopenharmony_ci * 11608c2ecf20Sopenharmony_ci * Get the byte offset range of @vr_die and stores it in @buf as 11618c2ecf20Sopenharmony_ci * "@<function_name+[NN-NN,NN-NN]>". 11628c2ecf20Sopenharmony_ci */ 11638c2ecf20Sopenharmony_ciint die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf) 11648c2ecf20Sopenharmony_ci{ 11658c2ecf20Sopenharmony_ci int ret = 0; 11668c2ecf20Sopenharmony_ci Dwarf_Addr base; 11678c2ecf20Sopenharmony_ci Dwarf_Addr start, end; 11688c2ecf20Sopenharmony_ci Dwarf_Addr entry; 11698c2ecf20Sopenharmony_ci Dwarf_Op *op; 11708c2ecf20Sopenharmony_ci size_t nops; 11718c2ecf20Sopenharmony_ci size_t offset = 0; 11728c2ecf20Sopenharmony_ci Dwarf_Attribute attr; 11738c2ecf20Sopenharmony_ci bool first = true; 11748c2ecf20Sopenharmony_ci const char *name; 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci ret = die_entrypc(sp_die, &entry); 11778c2ecf20Sopenharmony_ci if (ret) 11788c2ecf20Sopenharmony_ci return ret; 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci name = dwarf_diename(sp_die); 11818c2ecf20Sopenharmony_ci if (!name) 11828c2ecf20Sopenharmony_ci return -ENOENT; 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL) 11858c2ecf20Sopenharmony_ci return -EINVAL; 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci while ((offset = dwarf_getlocations(&attr, offset, &base, 11888c2ecf20Sopenharmony_ci &start, &end, &op, &nops)) > 0) { 11898c2ecf20Sopenharmony_ci if (start == 0) { 11908c2ecf20Sopenharmony_ci /* Single Location Descriptions */ 11918c2ecf20Sopenharmony_ci ret = die_get_var_innermost_scope(sp_die, vr_die, buf); 11928c2ecf20Sopenharmony_ci goto out; 11938c2ecf20Sopenharmony_ci } 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci /* Location Lists */ 11968c2ecf20Sopenharmony_ci start -= entry; 11978c2ecf20Sopenharmony_ci end -= entry; 11988c2ecf20Sopenharmony_ci if (first) { 11998c2ecf20Sopenharmony_ci ret = strbuf_addf(buf, "@<%s+[%" PRIu64 "-%" PRIu64, 12008c2ecf20Sopenharmony_ci name, start, end); 12018c2ecf20Sopenharmony_ci first = false; 12028c2ecf20Sopenharmony_ci } else { 12038c2ecf20Sopenharmony_ci ret = strbuf_addf(buf, ",%" PRIu64 "-%" PRIu64, 12048c2ecf20Sopenharmony_ci start, end); 12058c2ecf20Sopenharmony_ci } 12068c2ecf20Sopenharmony_ci if (ret < 0) 12078c2ecf20Sopenharmony_ci goto out; 12088c2ecf20Sopenharmony_ci } 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci if (!first) 12118c2ecf20Sopenharmony_ci ret = strbuf_add(buf, "]>", 2); 12128c2ecf20Sopenharmony_ciout: 12138c2ecf20Sopenharmony_ci return ret; 12148c2ecf20Sopenharmony_ci} 12158c2ecf20Sopenharmony_ci#else 12168c2ecf20Sopenharmony_ciint die_get_var_range(Dwarf_Die *sp_die __maybe_unused, 12178c2ecf20Sopenharmony_ci Dwarf_Die *vr_die __maybe_unused, 12188c2ecf20Sopenharmony_ci struct strbuf *buf __maybe_unused) 12198c2ecf20Sopenharmony_ci{ 12208c2ecf20Sopenharmony_ci return -ENOTSUP; 12218c2ecf20Sopenharmony_ci} 12228c2ecf20Sopenharmony_ci#endif 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci/* 12258c2ecf20Sopenharmony_ci * die_has_loclist - Check if DW_AT_location of @vr_die is a location list 12268c2ecf20Sopenharmony_ci * @vr_die: a variable DIE 12278c2ecf20Sopenharmony_ci */ 12288c2ecf20Sopenharmony_cistatic bool die_has_loclist(Dwarf_Die *vr_die) 12298c2ecf20Sopenharmony_ci{ 12308c2ecf20Sopenharmony_ci Dwarf_Attribute loc; 12318c2ecf20Sopenharmony_ci int tag = dwarf_tag(vr_die); 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci if (tag != DW_TAG_formal_parameter && 12348c2ecf20Sopenharmony_ci tag != DW_TAG_variable) 12358c2ecf20Sopenharmony_ci return false; 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci return (dwarf_attr_integrate(vr_die, DW_AT_location, &loc) && 12388c2ecf20Sopenharmony_ci dwarf_whatform(&loc) == DW_FORM_sec_offset); 12398c2ecf20Sopenharmony_ci} 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci/* 12428c2ecf20Sopenharmony_ci * die_is_optimized_target - Check if target program is compiled with 12438c2ecf20Sopenharmony_ci * optimization 12448c2ecf20Sopenharmony_ci * @cu_die: a CU DIE 12458c2ecf20Sopenharmony_ci * 12468c2ecf20Sopenharmony_ci * For any object in given CU whose DW_AT_location is a location list, 12478c2ecf20Sopenharmony_ci * target program is compiled with optimization. This is applicable to 12488c2ecf20Sopenharmony_ci * clang as well. 12498c2ecf20Sopenharmony_ci */ 12508c2ecf20Sopenharmony_cibool die_is_optimized_target(Dwarf_Die *cu_die) 12518c2ecf20Sopenharmony_ci{ 12528c2ecf20Sopenharmony_ci Dwarf_Die tmp_die; 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci if (die_has_loclist(cu_die)) 12558c2ecf20Sopenharmony_ci return true; 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci if (!dwarf_child(cu_die, &tmp_die) && 12588c2ecf20Sopenharmony_ci die_is_optimized_target(&tmp_die)) 12598c2ecf20Sopenharmony_ci return true; 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci if (!dwarf_siblingof(cu_die, &tmp_die) && 12628c2ecf20Sopenharmony_ci die_is_optimized_target(&tmp_die)) 12638c2ecf20Sopenharmony_ci return true; 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci return false; 12668c2ecf20Sopenharmony_ci} 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci/* 12698c2ecf20Sopenharmony_ci * die_search_idx - Search index of given line address 12708c2ecf20Sopenharmony_ci * @lines: Line records of single CU 12718c2ecf20Sopenharmony_ci * @nr_lines: Number of @lines 12728c2ecf20Sopenharmony_ci * @addr: address we are looking for 12738c2ecf20Sopenharmony_ci * @idx: index to be set by this function (return value) 12748c2ecf20Sopenharmony_ci * 12758c2ecf20Sopenharmony_ci * Search for @addr by looping over every lines of CU. If address 12768c2ecf20Sopenharmony_ci * matches, set index of that line in @idx. Note that single source 12778c2ecf20Sopenharmony_ci * line can have multiple line records. i.e. single source line can 12788c2ecf20Sopenharmony_ci * have multiple index. 12798c2ecf20Sopenharmony_ci */ 12808c2ecf20Sopenharmony_cistatic bool die_search_idx(Dwarf_Lines *lines, unsigned long nr_lines, 12818c2ecf20Sopenharmony_ci Dwarf_Addr addr, unsigned long *idx) 12828c2ecf20Sopenharmony_ci{ 12838c2ecf20Sopenharmony_ci unsigned long i; 12848c2ecf20Sopenharmony_ci Dwarf_Addr tmp; 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci for (i = 0; i < nr_lines; i++) { 12878c2ecf20Sopenharmony_ci if (dwarf_lineaddr(dwarf_onesrcline(lines, i), &tmp)) 12888c2ecf20Sopenharmony_ci return false; 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci if (tmp == addr) { 12918c2ecf20Sopenharmony_ci *idx = i; 12928c2ecf20Sopenharmony_ci return true; 12938c2ecf20Sopenharmony_ci } 12948c2ecf20Sopenharmony_ci } 12958c2ecf20Sopenharmony_ci return false; 12968c2ecf20Sopenharmony_ci} 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci/* 12998c2ecf20Sopenharmony_ci * die_get_postprologue_addr - Search next address after function prologue 13008c2ecf20Sopenharmony_ci * @entrypc_idx: entrypc index 13018c2ecf20Sopenharmony_ci * @lines: Line records of single CU 13028c2ecf20Sopenharmony_ci * @nr_lines: Number of @lines 13038c2ecf20Sopenharmony_ci * @hignpc: high PC address of function 13048c2ecf20Sopenharmony_ci * @postprologue_addr: Next address after function prologue (return value) 13058c2ecf20Sopenharmony_ci * 13068c2ecf20Sopenharmony_ci * Look for prologue-end marker. If there is no explicit marker, return 13078c2ecf20Sopenharmony_ci * address of next line record or next source line. 13088c2ecf20Sopenharmony_ci */ 13098c2ecf20Sopenharmony_cistatic bool die_get_postprologue_addr(unsigned long entrypc_idx, 13108c2ecf20Sopenharmony_ci Dwarf_Lines *lines, 13118c2ecf20Sopenharmony_ci unsigned long nr_lines, 13128c2ecf20Sopenharmony_ci Dwarf_Addr highpc, 13138c2ecf20Sopenharmony_ci Dwarf_Addr *postprologue_addr) 13148c2ecf20Sopenharmony_ci{ 13158c2ecf20Sopenharmony_ci unsigned long i; 13168c2ecf20Sopenharmony_ci int entrypc_lno, lno; 13178c2ecf20Sopenharmony_ci Dwarf_Line *line; 13188c2ecf20Sopenharmony_ci Dwarf_Addr addr; 13198c2ecf20Sopenharmony_ci bool p_end; 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci /* entrypc_lno is actual source line number */ 13228c2ecf20Sopenharmony_ci line = dwarf_onesrcline(lines, entrypc_idx); 13238c2ecf20Sopenharmony_ci if (dwarf_lineno(line, &entrypc_lno)) 13248c2ecf20Sopenharmony_ci return false; 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci for (i = entrypc_idx; i < nr_lines; i++) { 13278c2ecf20Sopenharmony_ci line = dwarf_onesrcline(lines, i); 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci if (dwarf_lineaddr(line, &addr) || 13308c2ecf20Sopenharmony_ci dwarf_lineno(line, &lno) || 13318c2ecf20Sopenharmony_ci dwarf_lineprologueend(line, &p_end)) 13328c2ecf20Sopenharmony_ci return false; 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci /* highpc is exclusive. [entrypc,highpc) */ 13358c2ecf20Sopenharmony_ci if (addr >= highpc) 13368c2ecf20Sopenharmony_ci break; 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci /* clang supports prologue-end marker */ 13398c2ecf20Sopenharmony_ci if (p_end) 13408c2ecf20Sopenharmony_ci break; 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci /* Actual next line in source */ 13438c2ecf20Sopenharmony_ci if (lno != entrypc_lno) 13448c2ecf20Sopenharmony_ci break; 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci /* 13478c2ecf20Sopenharmony_ci * Single source line can have multiple line records. 13488c2ecf20Sopenharmony_ci * For Example, 13498c2ecf20Sopenharmony_ci * void foo() { printf("hello\n"); } 13508c2ecf20Sopenharmony_ci * contains two line records. One points to declaration and 13518c2ecf20Sopenharmony_ci * other points to printf() line. Variable 'lno' won't get 13528c2ecf20Sopenharmony_ci * incremented in this case but 'i' will. 13538c2ecf20Sopenharmony_ci */ 13548c2ecf20Sopenharmony_ci if (i != entrypc_idx) 13558c2ecf20Sopenharmony_ci break; 13568c2ecf20Sopenharmony_ci } 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci dwarf_lineaddr(line, postprologue_addr); 13598c2ecf20Sopenharmony_ci if (*postprologue_addr >= highpc) 13608c2ecf20Sopenharmony_ci dwarf_lineaddr(dwarf_onesrcline(lines, i - 1), 13618c2ecf20Sopenharmony_ci postprologue_addr); 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci return true; 13648c2ecf20Sopenharmony_ci} 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci/* 13678c2ecf20Sopenharmony_ci * die_skip_prologue - Use next address after prologue as probe location 13688c2ecf20Sopenharmony_ci * @sp_die: a subprogram DIE 13698c2ecf20Sopenharmony_ci * @cu_die: a CU DIE 13708c2ecf20Sopenharmony_ci * @entrypc: entrypc of the function 13718c2ecf20Sopenharmony_ci * 13728c2ecf20Sopenharmony_ci * Function prologue prepares stack and registers before executing function 13738c2ecf20Sopenharmony_ci * logic. When target program is compiled without optimization, function 13748c2ecf20Sopenharmony_ci * parameter information is only valid after prologue. When we probe entrypc 13758c2ecf20Sopenharmony_ci * of the function, and try to record function parameter, it contains 13768c2ecf20Sopenharmony_ci * garbage value. 13778c2ecf20Sopenharmony_ci */ 13788c2ecf20Sopenharmony_civoid die_skip_prologue(Dwarf_Die *sp_die, Dwarf_Die *cu_die, 13798c2ecf20Sopenharmony_ci Dwarf_Addr *entrypc) 13808c2ecf20Sopenharmony_ci{ 13818c2ecf20Sopenharmony_ci size_t nr_lines = 0; 13828c2ecf20Sopenharmony_ci unsigned long entrypc_idx = 0; 13838c2ecf20Sopenharmony_ci Dwarf_Lines *lines = NULL; 13848c2ecf20Sopenharmony_ci Dwarf_Addr postprologue_addr; 13858c2ecf20Sopenharmony_ci Dwarf_Addr highpc; 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci if (dwarf_highpc(sp_die, &highpc)) 13888c2ecf20Sopenharmony_ci return; 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci if (dwarf_getsrclines(cu_die, &lines, &nr_lines)) 13918c2ecf20Sopenharmony_ci return; 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci if (!die_search_idx(lines, nr_lines, *entrypc, &entrypc_idx)) 13948c2ecf20Sopenharmony_ci return; 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci if (!die_get_postprologue_addr(entrypc_idx, lines, nr_lines, 13978c2ecf20Sopenharmony_ci highpc, &postprologue_addr)) 13988c2ecf20Sopenharmony_ci return; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci *entrypc = postprologue_addr; 14018c2ecf20Sopenharmony_ci} 1402