Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * dwarf-aux.c : libdw auxiliary interfaces
0004  */
0005 
0006 #include <errno.h>
0007 #include <inttypes.h>
0008 #include <stdbool.h>
0009 #include <stdlib.h>
0010 #include "debug.h"
0011 #include "dwarf-aux.h"
0012 #include "strbuf.h"
0013 #include "string2.h"
0014 
0015 /**
0016  * cu_find_realpath - Find the realpath of the target file
0017  * @cu_die: A DIE(dwarf information entry) of CU(compilation Unit)
0018  * @fname:  The tail filename of the target file
0019  *
0020  * Find the real(long) path of @fname in @cu_die.
0021  */
0022 const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname)
0023 {
0024     Dwarf_Files *files;
0025     size_t nfiles, i;
0026     const char *src = NULL;
0027     int ret;
0028 
0029     if (!fname)
0030         return NULL;
0031 
0032     ret = dwarf_getsrcfiles(cu_die, &files, &nfiles);
0033     if (ret != 0)
0034         return NULL;
0035 
0036     for (i = 0; i < nfiles; i++) {
0037         src = dwarf_filesrc(files, i, NULL, NULL);
0038         if (strtailcmp(src, fname) == 0)
0039             break;
0040     }
0041     if (i == nfiles)
0042         return NULL;
0043     return src;
0044 }
0045 
0046 /**
0047  * cu_get_comp_dir - Get the path of compilation directory
0048  * @cu_die: a CU DIE
0049  *
0050  * Get the path of compilation directory of given @cu_die.
0051  * Since this depends on DW_AT_comp_dir, older gcc will not
0052  * embedded it. In that case, this returns NULL.
0053  */
0054 const char *cu_get_comp_dir(Dwarf_Die *cu_die)
0055 {
0056     Dwarf_Attribute attr;
0057     if (dwarf_attr(cu_die, DW_AT_comp_dir, &attr) == NULL)
0058         return NULL;
0059     return dwarf_formstring(&attr);
0060 }
0061 
0062 /* Unlike dwarf_getsrc_die(), cu_getsrc_die() only returns statement line */
0063 static Dwarf_Line *cu_getsrc_die(Dwarf_Die *cu_die, Dwarf_Addr addr)
0064 {
0065     Dwarf_Addr laddr;
0066     Dwarf_Lines *lines;
0067     Dwarf_Line *line;
0068     size_t nlines, l, u, n;
0069     bool flag;
0070 
0071     if (dwarf_getsrclines(cu_die, &lines, &nlines) != 0 ||
0072         nlines == 0)
0073         return NULL;
0074 
0075     /* Lines are sorted by address, use binary search */
0076     l = 0; u = nlines - 1;
0077     while (l < u) {
0078         n = u - (u - l) / 2;
0079         line = dwarf_onesrcline(lines, n);
0080         if (!line || dwarf_lineaddr(line, &laddr) != 0)
0081             return NULL;
0082         if (addr < laddr)
0083             u = n - 1;
0084         else
0085             l = n;
0086     }
0087     /* Going backward to find the lowest line */
0088     do {
0089         line = dwarf_onesrcline(lines, --l);
0090         if (!line || dwarf_lineaddr(line, &laddr) != 0)
0091             return NULL;
0092     } while (laddr == addr);
0093     l++;
0094     /* Going forward to find the statement line */
0095     do {
0096         line = dwarf_onesrcline(lines, l++);
0097         if (!line || dwarf_lineaddr(line, &laddr) != 0 ||
0098             dwarf_linebeginstatement(line, &flag) != 0)
0099             return NULL;
0100         if (laddr > addr)
0101             return NULL;
0102     } while (!flag);
0103 
0104     return line;
0105 }
0106 
0107 /**
0108  * cu_find_lineinfo - Get a line number and file name for given address
0109  * @cu_die: a CU DIE
0110  * @addr: An address
0111  * @fname: a pointer which returns the file name string
0112  * @lineno: a pointer which returns the line number
0113  *
0114  * Find a line number and file name for @addr in @cu_die.
0115  */
0116 int cu_find_lineinfo(Dwarf_Die *cu_die, Dwarf_Addr addr,
0117              const char **fname, int *lineno)
0118 {
0119     Dwarf_Line *line;
0120     Dwarf_Die die_mem;
0121     Dwarf_Addr faddr;
0122 
0123     if (die_find_realfunc(cu_die, addr, &die_mem)
0124         && die_entrypc(&die_mem, &faddr) == 0 &&
0125         faddr == addr) {
0126         *fname = dwarf_decl_file(&die_mem);
0127         dwarf_decl_line(&die_mem, lineno);
0128         goto out;
0129     }
0130 
0131     line = cu_getsrc_die(cu_die, addr);
0132     if (line && dwarf_lineno(line, lineno) == 0) {
0133         *fname = dwarf_linesrc(line, NULL, NULL);
0134         if (!*fname)
0135             /* line number is useless without filename */
0136             *lineno = 0;
0137     }
0138 
0139 out:
0140     return *lineno ?: -ENOENT;
0141 }
0142 
0143 static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data);
0144 
0145 /**
0146  * cu_walk_functions_at - Walk on function DIEs at given address
0147  * @cu_die: A CU DIE
0148  * @addr: An address
0149  * @callback: A callback which called with found DIEs
0150  * @data: A user data
0151  *
0152  * Walk on function DIEs at given @addr in @cu_die. Passed DIEs
0153  * should be subprogram or inlined-subroutines.
0154  */
0155 int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr,
0156             int (*callback)(Dwarf_Die *, void *), void *data)
0157 {
0158     Dwarf_Die die_mem;
0159     Dwarf_Die *sc_die;
0160     int ret = -ENOENT;
0161 
0162     /* Inlined function could be recursive. Trace it until fail */
0163     for (sc_die = die_find_realfunc(cu_die, addr, &die_mem);
0164          sc_die != NULL;
0165          sc_die = die_find_child(sc_die, __die_find_inline_cb, &addr,
0166                      &die_mem)) {
0167         ret = callback(sc_die, data);
0168         if (ret)
0169             break;
0170     }
0171 
0172     return ret;
0173 
0174 }
0175 
0176 /**
0177  * die_get_linkage_name - Get the linkage name of the object
0178  * @dw_die: A DIE of the object
0179  *
0180  * Get the linkage name attribute of given @dw_die.
0181  * For C++ binary, the linkage name will be the mangled symbol.
0182  */
0183 const char *die_get_linkage_name(Dwarf_Die *dw_die)
0184 {
0185     Dwarf_Attribute attr;
0186 
0187     if (dwarf_attr_integrate(dw_die, DW_AT_linkage_name, &attr) == NULL)
0188         return NULL;
0189     return dwarf_formstring(&attr);
0190 }
0191 
0192 /**
0193  * die_compare_name - Compare diename and tname
0194  * @dw_die: a DIE
0195  * @tname: a string of target name
0196  *
0197  * Compare the name of @dw_die and @tname. Return false if @dw_die has no name.
0198  */
0199 bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
0200 {
0201     const char *name;
0202 
0203     name = dwarf_diename(dw_die);
0204     return name ? (strcmp(tname, name) == 0) : false;
0205 }
0206 
0207 /**
0208  * die_match_name - Match diename/linkage name and glob
0209  * @dw_die: a DIE
0210  * @glob: a string of target glob pattern
0211  *
0212  * Glob matching the name of @dw_die and @glob. Return false if matching fail.
0213  * This also match linkage name.
0214  */
0215 bool die_match_name(Dwarf_Die *dw_die, const char *glob)
0216 {
0217     const char *name;
0218 
0219     name = dwarf_diename(dw_die);
0220     if (name && strglobmatch(name, glob))
0221         return true;
0222     /* fall back to check linkage name */
0223     name = die_get_linkage_name(dw_die);
0224     if (name && strglobmatch(name, glob))
0225         return true;
0226 
0227     return false;
0228 }
0229 
0230 /**
0231  * die_get_call_lineno - Get callsite line number of inline-function instance
0232  * @in_die: a DIE of an inlined function instance
0233  *
0234  * Get call-site line number of @in_die. This means from where the inline
0235  * function is called.
0236  */
0237 int die_get_call_lineno(Dwarf_Die *in_die)
0238 {
0239     Dwarf_Attribute attr;
0240     Dwarf_Word ret;
0241 
0242     if (!dwarf_attr(in_die, DW_AT_call_line, &attr))
0243         return -ENOENT;
0244 
0245     dwarf_formudata(&attr, &ret);
0246     return (int)ret;
0247 }
0248 
0249 /**
0250  * die_get_type - Get type DIE
0251  * @vr_die: a DIE of a variable
0252  * @die_mem: where to store a type DIE
0253  *
0254  * Get a DIE of the type of given variable (@vr_die), and store
0255  * it to die_mem. Return NULL if fails to get a type DIE.
0256  */
0257 Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
0258 {
0259     Dwarf_Attribute attr;
0260 
0261     if (dwarf_attr_integrate(vr_die, DW_AT_type, &attr) &&
0262         dwarf_formref_die(&attr, die_mem))
0263         return die_mem;
0264     else
0265         return NULL;
0266 }
0267 
0268 /* Get a type die, but skip qualifiers */
0269 static Dwarf_Die *__die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
0270 {
0271     int tag;
0272 
0273     do {
0274         vr_die = die_get_type(vr_die, die_mem);
0275         if (!vr_die)
0276             break;
0277         tag = dwarf_tag(vr_die);
0278     } while (tag == DW_TAG_const_type ||
0279          tag == DW_TAG_restrict_type ||
0280          tag == DW_TAG_volatile_type ||
0281          tag == DW_TAG_shared_type);
0282 
0283     return vr_die;
0284 }
0285 
0286 /**
0287  * die_get_real_type - Get a type die, but skip qualifiers and typedef
0288  * @vr_die: a DIE of a variable
0289  * @die_mem: where to store a type DIE
0290  *
0291  * Get a DIE of the type of given variable (@vr_die), and store
0292  * it to die_mem. Return NULL if fails to get a type DIE.
0293  * If the type is qualifiers (e.g. const) or typedef, this skips it
0294  * and tries to find real type (structure or basic types, e.g. int).
0295  */
0296 Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
0297 {
0298     do {
0299         vr_die = __die_get_real_type(vr_die, die_mem);
0300     } while (vr_die && dwarf_tag(vr_die) == DW_TAG_typedef);
0301 
0302     return vr_die;
0303 }
0304 
0305 /* Get attribute and translate it as a udata */
0306 static int die_get_attr_udata(Dwarf_Die *tp_die, unsigned int attr_name,
0307                   Dwarf_Word *result)
0308 {
0309     Dwarf_Attribute attr;
0310 
0311     if (dwarf_attr(tp_die, attr_name, &attr) == NULL ||
0312         dwarf_formudata(&attr, result) != 0)
0313         return -ENOENT;
0314 
0315     return 0;
0316 }
0317 
0318 /* Get attribute and translate it as a sdata */
0319 static int die_get_attr_sdata(Dwarf_Die *tp_die, unsigned int attr_name,
0320                   Dwarf_Sword *result)
0321 {
0322     Dwarf_Attribute attr;
0323 
0324     if (dwarf_attr(tp_die, attr_name, &attr) == NULL ||
0325         dwarf_formsdata(&attr, result) != 0)
0326         return -ENOENT;
0327 
0328     return 0;
0329 }
0330 
0331 /**
0332  * die_is_signed_type - Check whether a type DIE is signed or not
0333  * @tp_die: a DIE of a type
0334  *
0335  * Get the encoding of @tp_die and return true if the encoding
0336  * is signed.
0337  */
0338 bool die_is_signed_type(Dwarf_Die *tp_die)
0339 {
0340     Dwarf_Word ret;
0341 
0342     if (die_get_attr_udata(tp_die, DW_AT_encoding, &ret))
0343         return false;
0344 
0345     return (ret == DW_ATE_signed_char || ret == DW_ATE_signed ||
0346         ret == DW_ATE_signed_fixed);
0347 }
0348 
0349 /**
0350  * die_is_func_def - Ensure that this DIE is a subprogram and definition
0351  * @dw_die: a DIE
0352  *
0353  * Ensure that this DIE is a subprogram and NOT a declaration. This
0354  * returns true if @dw_die is a function definition.
0355  **/
0356 bool die_is_func_def(Dwarf_Die *dw_die)
0357 {
0358     Dwarf_Attribute attr;
0359     Dwarf_Addr addr = 0;
0360 
0361     if (dwarf_tag(dw_die) != DW_TAG_subprogram)
0362         return false;
0363 
0364     if (dwarf_attr(dw_die, DW_AT_declaration, &attr))
0365         return false;
0366 
0367     /*
0368      * DW_AT_declaration can be lost from function declaration
0369      * by gcc's bug #97060.
0370      * So we need to check this subprogram DIE has DW_AT_inline
0371      * or an entry address.
0372      */
0373     if (!dwarf_attr(dw_die, DW_AT_inline, &attr) &&
0374         die_entrypc(dw_die, &addr) < 0)
0375         return false;
0376 
0377     return true;
0378 }
0379 
0380 /**
0381  * die_entrypc - Returns entry PC (the lowest address) of a DIE
0382  * @dw_die: a DIE
0383  * @addr: where to store entry PC
0384  *
0385  * Since dwarf_entrypc() does not return entry PC if the DIE has only address
0386  * range, we have to use this to retrieve the lowest address from the address
0387  * range attribute.
0388  */
0389 int die_entrypc(Dwarf_Die *dw_die, Dwarf_Addr *addr)
0390 {
0391     Dwarf_Addr base, end;
0392     Dwarf_Attribute attr;
0393 
0394     if (!addr)
0395         return -EINVAL;
0396 
0397     if (dwarf_entrypc(dw_die, addr) == 0)
0398         return 0;
0399 
0400     /*
0401      *  Since the dwarf_ranges() will return 0 if there is no
0402      * DW_AT_ranges attribute, we should check it first.
0403      */
0404     if (!dwarf_attr(dw_die, DW_AT_ranges, &attr))
0405         return -ENOENT;
0406 
0407     return dwarf_ranges(dw_die, 0, &base, addr, &end) < 0 ? -ENOENT : 0;
0408 }
0409 
0410 /**
0411  * die_is_func_instance - Ensure that this DIE is an instance of a subprogram
0412  * @dw_die: a DIE
0413  *
0414  * Ensure that this DIE is an instance (which has an entry address).
0415  * This returns true if @dw_die is a function instance. If not, the @dw_die
0416  * must be a prototype. You can use die_walk_instances() to find actual
0417  * instances.
0418  **/
0419 bool die_is_func_instance(Dwarf_Die *dw_die)
0420 {
0421     Dwarf_Addr tmp;
0422     Dwarf_Attribute attr_mem;
0423     int tag = dwarf_tag(dw_die);
0424 
0425     if (tag != DW_TAG_subprogram &&
0426         tag != DW_TAG_inlined_subroutine)
0427         return false;
0428 
0429     return dwarf_entrypc(dw_die, &tmp) == 0 ||
0430         dwarf_attr(dw_die, DW_AT_ranges, &attr_mem) != NULL;
0431 }
0432 
0433 /**
0434  * die_get_data_member_location - Get the data-member offset
0435  * @mb_die: a DIE of a member of a data structure
0436  * @offs: The offset of the member in the data structure
0437  *
0438  * Get the offset of @mb_die in the data structure including @mb_die, and
0439  * stores result offset to @offs. If any error occurs this returns errno.
0440  */
0441 int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs)
0442 {
0443     Dwarf_Attribute attr;
0444     Dwarf_Op *expr;
0445     size_t nexpr;
0446     int ret;
0447 
0448     if (dwarf_attr(mb_die, DW_AT_data_member_location, &attr) == NULL)
0449         return -ENOENT;
0450 
0451     if (dwarf_formudata(&attr, offs) != 0) {
0452         /* DW_AT_data_member_location should be DW_OP_plus_uconst */
0453         ret = dwarf_getlocation(&attr, &expr, &nexpr);
0454         if (ret < 0 || nexpr == 0)
0455             return -ENOENT;
0456 
0457         if (expr[0].atom != DW_OP_plus_uconst || nexpr != 1) {
0458             pr_debug("Unable to get offset:Unexpected OP %x (%zd)\n",
0459                  expr[0].atom, nexpr);
0460             return -ENOTSUP;
0461         }
0462         *offs = (Dwarf_Word)expr[0].number;
0463     }
0464     return 0;
0465 }
0466 
0467 /* Get the call file index number in CU DIE */
0468 static int die_get_call_fileno(Dwarf_Die *in_die)
0469 {
0470     Dwarf_Sword idx;
0471 
0472     if (die_get_attr_sdata(in_die, DW_AT_call_file, &idx) == 0)
0473         return (int)idx;
0474     else
0475         return -ENOENT;
0476 }
0477 
0478 /* Get the declared file index number in CU DIE */
0479 static int die_get_decl_fileno(Dwarf_Die *pdie)
0480 {
0481     Dwarf_Sword idx;
0482 
0483     if (die_get_attr_sdata(pdie, DW_AT_decl_file, &idx) == 0)
0484         return (int)idx;
0485     else
0486         return -ENOENT;
0487 }
0488 
0489 /**
0490  * die_get_call_file - Get callsite file name of inlined function instance
0491  * @in_die: a DIE of an inlined function instance
0492  *
0493  * Get call-site file name of @in_die. This means from which file the inline
0494  * function is called.
0495  */
0496 const char *die_get_call_file(Dwarf_Die *in_die)
0497 {
0498     Dwarf_Die cu_die;
0499     Dwarf_Files *files;
0500     int idx;
0501 
0502     idx = die_get_call_fileno(in_die);
0503     if (idx < 0 || !dwarf_diecu(in_die, &cu_die, NULL, NULL) ||
0504         dwarf_getsrcfiles(&cu_die, &files, NULL) != 0)
0505         return NULL;
0506 
0507     return dwarf_filesrc(files, idx, NULL, NULL);
0508 }
0509 
0510 
0511 /**
0512  * die_find_child - Generic DIE search function in DIE tree
0513  * @rt_die: a root DIE
0514  * @callback: a callback function
0515  * @data: a user data passed to the callback function
0516  * @die_mem: a buffer for result DIE
0517  *
0518  * Trace DIE tree from @rt_die and call @callback for each child DIE.
0519  * If @callback returns DIE_FIND_CB_END, this stores the DIE into
0520  * @die_mem and returns it. If @callback returns DIE_FIND_CB_CONTINUE,
0521  * this continues to trace the tree. Optionally, @callback can return
0522  * DIE_FIND_CB_CHILD and DIE_FIND_CB_SIBLING, those means trace only
0523  * the children and trace only the siblings respectively.
0524  * Returns NULL if @callback can't find any appropriate DIE.
0525  */
0526 Dwarf_Die *die_find_child(Dwarf_Die *rt_die,
0527               int (*callback)(Dwarf_Die *, void *),
0528               void *data, Dwarf_Die *die_mem)
0529 {
0530     Dwarf_Die child_die;
0531     int ret;
0532 
0533     ret = dwarf_child(rt_die, die_mem);
0534     if (ret != 0)
0535         return NULL;
0536 
0537     do {
0538         ret = callback(die_mem, data);
0539         if (ret == DIE_FIND_CB_END)
0540             return die_mem;
0541 
0542         if ((ret & DIE_FIND_CB_CHILD) &&
0543             die_find_child(die_mem, callback, data, &child_die)) {
0544             memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
0545             return die_mem;
0546         }
0547     } while ((ret & DIE_FIND_CB_SIBLING) &&
0548          dwarf_siblingof(die_mem, die_mem) == 0);
0549 
0550     return NULL;
0551 }
0552 
0553 struct __addr_die_search_param {
0554     Dwarf_Addr  addr;
0555     Dwarf_Die   *die_mem;
0556 };
0557 
0558 static int __die_search_func_tail_cb(Dwarf_Die *fn_die, void *data)
0559 {
0560     struct __addr_die_search_param *ad = data;
0561     Dwarf_Addr addr = 0;
0562 
0563     if (dwarf_tag(fn_die) == DW_TAG_subprogram &&
0564         !dwarf_highpc(fn_die, &addr) &&
0565         addr == ad->addr) {
0566         memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die));
0567         return DWARF_CB_ABORT;
0568     }
0569     return DWARF_CB_OK;
0570 }
0571 
0572 /**
0573  * die_find_tailfunc - Search for a non-inlined function with tail call at
0574  * given address
0575  * @cu_die: a CU DIE which including @addr
0576  * @addr: target address
0577  * @die_mem: a buffer for result DIE
0578  *
0579  * Search for a non-inlined function DIE with tail call at @addr. Stores the
0580  * DIE to @die_mem and returns it if found. Returns NULL if failed.
0581  */
0582 Dwarf_Die *die_find_tailfunc(Dwarf_Die *cu_die, Dwarf_Addr addr,
0583                     Dwarf_Die *die_mem)
0584 {
0585     struct __addr_die_search_param ad;
0586     ad.addr = addr;
0587     ad.die_mem = die_mem;
0588     /* dwarf_getscopes can't find subprogram. */
0589     if (!dwarf_getfuncs(cu_die, __die_search_func_tail_cb, &ad, 0))
0590         return NULL;
0591     else
0592         return die_mem;
0593 }
0594 
0595 /* die_find callback for non-inlined function search */
0596 static int __die_search_func_cb(Dwarf_Die *fn_die, void *data)
0597 {
0598     struct __addr_die_search_param *ad = data;
0599 
0600     /*
0601      * Since a declaration entry doesn't has given pc, this always returns
0602      * function definition entry.
0603      */
0604     if (dwarf_tag(fn_die) == DW_TAG_subprogram &&
0605         dwarf_haspc(fn_die, ad->addr)) {
0606         memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die));
0607         return DWARF_CB_ABORT;
0608     }
0609     return DWARF_CB_OK;
0610 }
0611 
0612 /**
0613  * die_find_realfunc - Search a non-inlined function at given address
0614  * @cu_die: a CU DIE which including @addr
0615  * @addr: target address
0616  * @die_mem: a buffer for result DIE
0617  *
0618  * Search a non-inlined function DIE which includes @addr. Stores the
0619  * DIE to @die_mem and returns it if found. Returns NULL if failed.
0620  */
0621 Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr,
0622                     Dwarf_Die *die_mem)
0623 {
0624     struct __addr_die_search_param ad;
0625     ad.addr = addr;
0626     ad.die_mem = die_mem;
0627     /* dwarf_getscopes can't find subprogram. */
0628     if (!dwarf_getfuncs(cu_die, __die_search_func_cb, &ad, 0))
0629         return NULL;
0630     else
0631         return die_mem;
0632 }
0633 
0634 /* die_find callback for inline function search */
0635 static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data)
0636 {
0637     Dwarf_Addr *addr = data;
0638 
0639     if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine &&
0640         dwarf_haspc(die_mem, *addr))
0641         return DIE_FIND_CB_END;
0642 
0643     return DIE_FIND_CB_CONTINUE;
0644 }
0645 
0646 /**
0647  * die_find_top_inlinefunc - Search the top inlined function at given address
0648  * @sp_die: a subprogram DIE which including @addr
0649  * @addr: target address
0650  * @die_mem: a buffer for result DIE
0651  *
0652  * Search an inlined function DIE which includes @addr. Stores the
0653  * DIE to @die_mem and returns it if found. Returns NULL if failed.
0654  * Even if several inlined functions are expanded recursively, this
0655  * doesn't trace it down, and returns the topmost one.
0656  */
0657 Dwarf_Die *die_find_top_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
0658                    Dwarf_Die *die_mem)
0659 {
0660     return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem);
0661 }
0662 
0663 /**
0664  * die_find_inlinefunc - Search an inlined function at given address
0665  * @sp_die: a subprogram DIE which including @addr
0666  * @addr: target address
0667  * @die_mem: a buffer for result DIE
0668  *
0669  * Search an inlined function DIE which includes @addr. Stores the
0670  * DIE to @die_mem and returns it if found. Returns NULL if failed.
0671  * If several inlined functions are expanded recursively, this trace
0672  * it down and returns deepest one.
0673  */
0674 Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
0675                    Dwarf_Die *die_mem)
0676 {
0677     Dwarf_Die tmp_die;
0678 
0679     sp_die = die_find_child(sp_die, __die_find_inline_cb, &addr, &tmp_die);
0680     if (!sp_die)
0681         return NULL;
0682 
0683     /* Inlined function could be recursive. Trace it until fail */
0684     while (sp_die) {
0685         memcpy(die_mem, sp_die, sizeof(Dwarf_Die));
0686         sp_die = die_find_child(sp_die, __die_find_inline_cb, &addr,
0687                     &tmp_die);
0688     }
0689 
0690     return die_mem;
0691 }
0692 
0693 struct __instance_walk_param {
0694     void    *addr;
0695     int (*callback)(Dwarf_Die *, void *);
0696     void    *data;
0697     int retval;
0698 };
0699 
0700 static int __die_walk_instances_cb(Dwarf_Die *inst, void *data)
0701 {
0702     struct __instance_walk_param *iwp = data;
0703     Dwarf_Attribute attr_mem;
0704     Dwarf_Die origin_mem;
0705     Dwarf_Attribute *attr;
0706     Dwarf_Die *origin;
0707     int tmp;
0708 
0709     if (!die_is_func_instance(inst))
0710         return DIE_FIND_CB_CONTINUE;
0711 
0712     attr = dwarf_attr(inst, DW_AT_abstract_origin, &attr_mem);
0713     if (attr == NULL)
0714         return DIE_FIND_CB_CONTINUE;
0715 
0716     origin = dwarf_formref_die(attr, &origin_mem);
0717     if (origin == NULL || origin->addr != iwp->addr)
0718         return DIE_FIND_CB_CONTINUE;
0719 
0720     /* Ignore redundant instances */
0721     if (dwarf_tag(inst) == DW_TAG_inlined_subroutine) {
0722         dwarf_decl_line(origin, &tmp);
0723         if (die_get_call_lineno(inst) == tmp) {
0724             tmp = die_get_decl_fileno(origin);
0725             if (die_get_call_fileno(inst) == tmp)
0726                 return DIE_FIND_CB_CONTINUE;
0727         }
0728     }
0729 
0730     iwp->retval = iwp->callback(inst, iwp->data);
0731 
0732     return (iwp->retval) ? DIE_FIND_CB_END : DIE_FIND_CB_CONTINUE;
0733 }
0734 
0735 /**
0736  * die_walk_instances - Walk on instances of given DIE
0737  * @or_die: an abstract original DIE
0738  * @callback: a callback function which is called with instance DIE
0739  * @data: user data
0740  *
0741  * Walk on the instances of give @in_die. @in_die must be an inlined function
0742  * declaration. This returns the return value of @callback if it returns
0743  * non-zero value, or -ENOENT if there is no instance.
0744  */
0745 int die_walk_instances(Dwarf_Die *or_die, int (*callback)(Dwarf_Die *, void *),
0746                void *data)
0747 {
0748     Dwarf_Die cu_die;
0749     Dwarf_Die die_mem;
0750     struct __instance_walk_param iwp = {
0751         .addr = or_die->addr,
0752         .callback = callback,
0753         .data = data,
0754         .retval = -ENOENT,
0755     };
0756 
0757     if (dwarf_diecu(or_die, &cu_die, NULL, NULL) == NULL)
0758         return -ENOENT;
0759 
0760     die_find_child(&cu_die, __die_walk_instances_cb, &iwp, &die_mem);
0761 
0762     return iwp.retval;
0763 }
0764 
0765 /* Line walker internal parameters */
0766 struct __line_walk_param {
0767     bool recursive;
0768     line_walk_callback_t callback;
0769     void *data;
0770     int retval;
0771 };
0772 
0773 static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data)
0774 {
0775     struct __line_walk_param *lw = data;
0776     Dwarf_Addr addr = 0;
0777     const char *fname;
0778     int lineno;
0779 
0780     if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) {
0781         fname = die_get_call_file(in_die);
0782         lineno = die_get_call_lineno(in_die);
0783         if (fname && lineno > 0 && die_entrypc(in_die, &addr) == 0) {
0784             lw->retval = lw->callback(fname, lineno, addr, lw->data);
0785             if (lw->retval != 0)
0786                 return DIE_FIND_CB_END;
0787         }
0788         if (!lw->recursive)
0789             return DIE_FIND_CB_SIBLING;
0790     }
0791 
0792     if (addr) {
0793         fname = dwarf_decl_file(in_die);
0794         if (fname && dwarf_decl_line(in_die, &lineno) == 0) {
0795             lw->retval = lw->callback(fname, lineno, addr, lw->data);
0796             if (lw->retval != 0)
0797                 return DIE_FIND_CB_END;
0798         }
0799     }
0800 
0801     /* Continue to search nested inlined function call-sites */
0802     return DIE_FIND_CB_CONTINUE;
0803 }
0804 
0805 /* Walk on lines of blocks included in given DIE */
0806 static int __die_walk_funclines(Dwarf_Die *sp_die, bool recursive,
0807                 line_walk_callback_t callback, void *data)
0808 {
0809     struct __line_walk_param lw = {
0810         .recursive = recursive,
0811         .callback = callback,
0812         .data = data,
0813         .retval = 0,
0814     };
0815     Dwarf_Die die_mem;
0816     Dwarf_Addr addr;
0817     const char *fname;
0818     int lineno;
0819 
0820     /* Handle function declaration line */
0821     fname = dwarf_decl_file(sp_die);
0822     if (fname && dwarf_decl_line(sp_die, &lineno) == 0 &&
0823         die_entrypc(sp_die, &addr) == 0) {
0824         lw.retval = callback(fname, lineno, addr, data);
0825         if (lw.retval != 0)
0826             goto done;
0827     }
0828     die_find_child(sp_die, __die_walk_funclines_cb, &lw, &die_mem);
0829 done:
0830     return lw.retval;
0831 }
0832 
0833 static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data)
0834 {
0835     struct __line_walk_param *lw = data;
0836 
0837     /*
0838      * Since inlined function can include another inlined function in
0839      * the same file, we need to walk in it recursively.
0840      */
0841     lw->retval = __die_walk_funclines(sp_die, true, lw->callback, lw->data);
0842     if (lw->retval != 0)
0843         return DWARF_CB_ABORT;
0844 
0845     return DWARF_CB_OK;
0846 }
0847 
0848 /**
0849  * die_walk_lines - Walk on lines inside given DIE
0850  * @rt_die: a root DIE (CU, subprogram or inlined_subroutine)
0851  * @callback: callback routine
0852  * @data: user data
0853  *
0854  * Walk on all lines inside given @rt_die and call @callback on each line.
0855  * If the @rt_die is a function, walk only on the lines inside the function,
0856  * otherwise @rt_die must be a CU DIE.
0857  * Note that this walks not only dwarf line list, but also function entries
0858  * and inline call-site.
0859  */
0860 int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data)
0861 {
0862     Dwarf_Lines *lines;
0863     Dwarf_Line *line;
0864     Dwarf_Addr addr;
0865     const char *fname, *decf = NULL, *inf = NULL;
0866     int lineno, ret = 0;
0867     int decl = 0, inl;
0868     Dwarf_Die die_mem, *cu_die;
0869     size_t nlines, i;
0870     bool flag;
0871 
0872     /* Get the CU die */
0873     if (dwarf_tag(rt_die) != DW_TAG_compile_unit) {
0874         cu_die = dwarf_diecu(rt_die, &die_mem, NULL, NULL);
0875         dwarf_decl_line(rt_die, &decl);
0876         decf = dwarf_decl_file(rt_die);
0877     } else
0878         cu_die = rt_die;
0879     if (!cu_die) {
0880         pr_debug2("Failed to get CU from given DIE.\n");
0881         return -EINVAL;
0882     }
0883 
0884     /* Get lines list in the CU */
0885     if (dwarf_getsrclines(cu_die, &lines, &nlines) != 0) {
0886         pr_debug2("Failed to get source lines on this CU.\n");
0887         return -ENOENT;
0888     }
0889     pr_debug2("Get %zd lines from this CU\n", nlines);
0890 
0891     /* Walk on the lines on lines list */
0892     for (i = 0; i < nlines; i++) {
0893         line = dwarf_onesrcline(lines, i);
0894         if (line == NULL ||
0895             dwarf_lineno(line, &lineno) != 0 ||
0896             dwarf_lineaddr(line, &addr) != 0) {
0897             pr_debug2("Failed to get line info. "
0898                   "Possible error in debuginfo.\n");
0899             continue;
0900         }
0901         /* Skip end-of-sequence */
0902         if (dwarf_lineendsequence(line, &flag) != 0 || flag)
0903             continue;
0904         /* Skip Non statement line-info */
0905         if (dwarf_linebeginstatement(line, &flag) != 0 || !flag)
0906             continue;
0907         /* Filter lines based on address */
0908         if (rt_die != cu_die) {
0909             /*
0910              * Address filtering
0911              * The line is included in given function, and
0912              * no inline block includes it.
0913              */
0914             if (!dwarf_haspc(rt_die, addr))
0915                 continue;
0916 
0917             if (die_find_inlinefunc(rt_die, addr, &die_mem)) {
0918                 /* Call-site check */
0919                 inf = die_get_call_file(&die_mem);
0920                 if ((inf && !strcmp(inf, decf)) &&
0921                     die_get_call_lineno(&die_mem) == lineno)
0922                     goto found;
0923 
0924                 dwarf_decl_line(&die_mem, &inl);
0925                 if (inl != decl ||
0926                     decf != dwarf_decl_file(&die_mem))
0927                     continue;
0928             }
0929         }
0930 found:
0931         /* Get source line */
0932         fname = dwarf_linesrc(line, NULL, NULL);
0933 
0934         ret = callback(fname, lineno, addr, data);
0935         if (ret != 0)
0936             return ret;
0937     }
0938 
0939     /*
0940      * Dwarf lines doesn't include function declarations and inlined
0941      * subroutines. We have to check functions list or given function.
0942      */
0943     if (rt_die != cu_die)
0944         /*
0945          * Don't need walk inlined functions recursively, because
0946          * inner inlined functions don't have the lines of the
0947          * specified function.
0948          */
0949         ret = __die_walk_funclines(rt_die, false, callback, data);
0950     else {
0951         struct __line_walk_param param = {
0952             .callback = callback,
0953             .data = data,
0954             .retval = 0,
0955         };
0956         dwarf_getfuncs(cu_die, __die_walk_culines_cb, &param, 0);
0957         ret = param.retval;
0958     }
0959 
0960     return ret;
0961 }
0962 
0963 struct __find_variable_param {
0964     const char *name;
0965     Dwarf_Addr addr;
0966 };
0967 
0968 static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data)
0969 {
0970     struct __find_variable_param *fvp = data;
0971     Dwarf_Attribute attr;
0972     int tag;
0973 
0974     tag = dwarf_tag(die_mem);
0975     if ((tag == DW_TAG_formal_parameter ||
0976          tag == DW_TAG_variable) &&
0977         die_compare_name(die_mem, fvp->name) &&
0978     /*
0979      * Does the DIE have location information or const value
0980      * or external instance?
0981      */
0982         (dwarf_attr(die_mem, DW_AT_external, &attr) ||
0983          dwarf_attr(die_mem, DW_AT_location, &attr) ||
0984          dwarf_attr(die_mem, DW_AT_const_value, &attr)))
0985         return DIE_FIND_CB_END;
0986     if (dwarf_haspc(die_mem, fvp->addr))
0987         return DIE_FIND_CB_CONTINUE;
0988     else
0989         return DIE_FIND_CB_SIBLING;
0990 }
0991 
0992 /**
0993  * die_find_variable_at - Find a given name variable at given address
0994  * @sp_die: a function DIE
0995  * @name: variable name
0996  * @addr: address
0997  * @die_mem: a buffer for result DIE
0998  *
0999  * Find a variable DIE called @name at @addr in @sp_die.
1000  */
1001 Dwarf_Die *die_find_variable_at(Dwarf_Die *sp_die, const char *name,
1002                 Dwarf_Addr addr, Dwarf_Die *die_mem)
1003 {
1004     struct __find_variable_param fvp = { .name = name, .addr = addr};
1005 
1006     return die_find_child(sp_die, __die_find_variable_cb, (void *)&fvp,
1007                   die_mem);
1008 }
1009 
1010 static int __die_find_member_cb(Dwarf_Die *die_mem, void *data)
1011 {
1012     const char *name = data;
1013 
1014     if (dwarf_tag(die_mem) == DW_TAG_member) {
1015         if (die_compare_name(die_mem, name))
1016             return DIE_FIND_CB_END;
1017         else if (!dwarf_diename(die_mem)) { /* Unnamed structure */
1018             Dwarf_Die type_die, tmp_die;
1019             if (die_get_type(die_mem, &type_die) &&
1020                 die_find_member(&type_die, name, &tmp_die))
1021                 return DIE_FIND_CB_END;
1022         }
1023     }
1024     return DIE_FIND_CB_SIBLING;
1025 }
1026 
1027 /**
1028  * die_find_member - Find a given name member in a data structure
1029  * @st_die: a data structure type DIE
1030  * @name: member name
1031  * @die_mem: a buffer for result DIE
1032  *
1033  * Find a member DIE called @name in @st_die.
1034  */
1035 Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
1036                Dwarf_Die *die_mem)
1037 {
1038     return die_find_child(st_die, __die_find_member_cb, (void *)name,
1039                   die_mem);
1040 }
1041 
1042 /**
1043  * die_get_typename - Get the name of given variable DIE
1044  * @vr_die: a variable DIE
1045  * @buf: a strbuf for result type name
1046  *
1047  * Get the name of @vr_die and stores it to @buf. Return 0 if succeeded.
1048  * and Return -ENOENT if failed to find type name.
1049  * Note that the result will stores typedef name if possible, and stores
1050  * "*(function_type)" if the type is a function pointer.
1051  */
1052 int die_get_typename(Dwarf_Die *vr_die, struct strbuf *buf)
1053 {
1054     Dwarf_Die type;
1055     int tag, ret;
1056     const char *tmp = "";
1057 
1058     if (__die_get_real_type(vr_die, &type) == NULL)
1059         return -ENOENT;
1060 
1061     tag = dwarf_tag(&type);
1062     if (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)
1063         tmp = "*";
1064     else if (tag == DW_TAG_subroutine_type) {
1065         /* Function pointer */
1066         return strbuf_add(buf, "(function_type)", 15);
1067     } else {
1068         if (!dwarf_diename(&type))
1069             return -ENOENT;
1070         if (tag == DW_TAG_union_type)
1071             tmp = "union ";
1072         else if (tag == DW_TAG_structure_type)
1073             tmp = "struct ";
1074         else if (tag == DW_TAG_enumeration_type)
1075             tmp = "enum ";
1076         /* Write a base name */
1077         return strbuf_addf(buf, "%s%s", tmp, dwarf_diename(&type));
1078     }
1079     ret = die_get_typename(&type, buf);
1080     return ret ? ret : strbuf_addstr(buf, tmp);
1081 }
1082 
1083 /**
1084  * die_get_varname - Get the name and type of given variable DIE
1085  * @vr_die: a variable DIE
1086  * @buf: a strbuf for type and variable name
1087  *
1088  * Get the name and type of @vr_die and stores it in @buf as "type\tname".
1089  */
1090 int die_get_varname(Dwarf_Die *vr_die, struct strbuf *buf)
1091 {
1092     int ret;
1093 
1094     ret = die_get_typename(vr_die, buf);
1095     if (ret < 0) {
1096         pr_debug("Failed to get type, make it unknown.\n");
1097         ret = strbuf_add(buf, " (unknown_type)", 14);
1098     }
1099 
1100     return ret < 0 ? ret : strbuf_addf(buf, "\t%s", dwarf_diename(vr_die));
1101 }
1102 
1103 #ifdef HAVE_DWARF_GETLOCATIONS_SUPPORT
1104 /**
1105  * die_get_var_innermost_scope - Get innermost scope range of given variable DIE
1106  * @sp_die: a subprogram DIE
1107  * @vr_die: a variable DIE
1108  * @buf: a strbuf for variable byte offset range
1109  *
1110  * Get the innermost scope range of @vr_die and stores it in @buf as
1111  * "@<function_name+[NN-NN,NN-NN]>".
1112  */
1113 static int die_get_var_innermost_scope(Dwarf_Die *sp_die, Dwarf_Die *vr_die,
1114                 struct strbuf *buf)
1115 {
1116     Dwarf_Die *scopes;
1117     int count;
1118     size_t offset = 0;
1119     Dwarf_Addr base;
1120     Dwarf_Addr start, end;
1121     Dwarf_Addr entry;
1122     int ret;
1123     bool first = true;
1124     const char *name;
1125 
1126     ret = die_entrypc(sp_die, &entry);
1127     if (ret)
1128         return ret;
1129 
1130     name = dwarf_diename(sp_die);
1131     if (!name)
1132         return -ENOENT;
1133 
1134     count = dwarf_getscopes_die(vr_die, &scopes);
1135 
1136     /* (*SCOPES)[1] is the DIE for the scope containing that scope */
1137     if (count <= 1) {
1138         ret = -EINVAL;
1139         goto out;
1140     }
1141 
1142     while ((offset = dwarf_ranges(&scopes[1], offset, &base,
1143                     &start, &end)) > 0) {
1144         start -= entry;
1145         end -= entry;
1146 
1147         if (first) {
1148             ret = strbuf_addf(buf, "@<%s+[%" PRIu64 "-%" PRIu64,
1149                       name, start, end);
1150             first = false;
1151         } else {
1152             ret = strbuf_addf(buf, ",%" PRIu64 "-%" PRIu64,
1153                       start, end);
1154         }
1155         if (ret < 0)
1156             goto out;
1157     }
1158 
1159     if (!first)
1160         ret = strbuf_add(buf, "]>", 2);
1161 
1162 out:
1163     free(scopes);
1164     return ret;
1165 }
1166 
1167 /**
1168  * die_get_var_range - Get byte offset range of given variable DIE
1169  * @sp_die: a subprogram DIE
1170  * @vr_die: a variable DIE
1171  * @buf: a strbuf for type and variable name and byte offset range
1172  *
1173  * Get the byte offset range of @vr_die and stores it in @buf as
1174  * "@<function_name+[NN-NN,NN-NN]>".
1175  */
1176 int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf)
1177 {
1178     int ret = 0;
1179     Dwarf_Addr base;
1180     Dwarf_Addr start, end;
1181     Dwarf_Addr entry;
1182     Dwarf_Op *op;
1183     size_t nops;
1184     size_t offset = 0;
1185     Dwarf_Attribute attr;
1186     bool first = true;
1187     const char *name;
1188 
1189     ret = die_entrypc(sp_die, &entry);
1190     if (ret)
1191         return ret;
1192 
1193     name = dwarf_diename(sp_die);
1194     if (!name)
1195         return -ENOENT;
1196 
1197     if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL)
1198         return -EINVAL;
1199 
1200     while ((offset = dwarf_getlocations(&attr, offset, &base,
1201                     &start, &end, &op, &nops)) > 0) {
1202         if (start == 0) {
1203             /* Single Location Descriptions */
1204             ret = die_get_var_innermost_scope(sp_die, vr_die, buf);
1205             goto out;
1206         }
1207 
1208         /* Location Lists */
1209         start -= entry;
1210         end -= entry;
1211         if (first) {
1212             ret = strbuf_addf(buf, "@<%s+[%" PRIu64 "-%" PRIu64,
1213                       name, start, end);
1214             first = false;
1215         } else {
1216             ret = strbuf_addf(buf, ",%" PRIu64 "-%" PRIu64,
1217                       start, end);
1218         }
1219         if (ret < 0)
1220             goto out;
1221     }
1222 
1223     if (!first)
1224         ret = strbuf_add(buf, "]>", 2);
1225 out:
1226     return ret;
1227 }
1228 #else
1229 int die_get_var_range(Dwarf_Die *sp_die __maybe_unused,
1230               Dwarf_Die *vr_die __maybe_unused,
1231               struct strbuf *buf __maybe_unused)
1232 {
1233     return -ENOTSUP;
1234 }
1235 #endif
1236 
1237 /*
1238  * die_has_loclist - Check if DW_AT_location of @vr_die is a location list
1239  * @vr_die: a variable DIE
1240  */
1241 static bool die_has_loclist(Dwarf_Die *vr_die)
1242 {
1243     Dwarf_Attribute loc;
1244     int tag = dwarf_tag(vr_die);
1245 
1246     if (tag != DW_TAG_formal_parameter &&
1247         tag != DW_TAG_variable)
1248         return false;
1249 
1250     return (dwarf_attr_integrate(vr_die, DW_AT_location, &loc) &&
1251         dwarf_whatform(&loc) == DW_FORM_sec_offset);
1252 }
1253 
1254 /*
1255  * die_is_optimized_target - Check if target program is compiled with
1256  * optimization
1257  * @cu_die: a CU DIE
1258  *
1259  * For any object in given CU whose DW_AT_location is a location list,
1260  * target program is compiled with optimization. This is applicable to
1261  * clang as well.
1262  */
1263 bool die_is_optimized_target(Dwarf_Die *cu_die)
1264 {
1265     Dwarf_Die tmp_die;
1266 
1267     if (die_has_loclist(cu_die))
1268         return true;
1269 
1270     if (!dwarf_child(cu_die, &tmp_die) &&
1271         die_is_optimized_target(&tmp_die))
1272         return true;
1273 
1274     if (!dwarf_siblingof(cu_die, &tmp_die) &&
1275         die_is_optimized_target(&tmp_die))
1276         return true;
1277 
1278     return false;
1279 }
1280 
1281 /*
1282  * die_search_idx - Search index of given line address
1283  * @lines: Line records of single CU
1284  * @nr_lines: Number of @lines
1285  * @addr: address we are looking for
1286  * @idx: index to be set by this function (return value)
1287  *
1288  * Search for @addr by looping over every lines of CU. If address
1289  * matches, set index of that line in @idx. Note that single source
1290  * line can have multiple line records. i.e. single source line can
1291  * have multiple index.
1292  */
1293 static bool die_search_idx(Dwarf_Lines *lines, unsigned long nr_lines,
1294                Dwarf_Addr addr, unsigned long *idx)
1295 {
1296     unsigned long i;
1297     Dwarf_Addr tmp;
1298 
1299     for (i = 0; i < nr_lines; i++) {
1300         if (dwarf_lineaddr(dwarf_onesrcline(lines, i), &tmp))
1301             return false;
1302 
1303         if (tmp == addr) {
1304             *idx = i;
1305             return true;
1306         }
1307     }
1308     return false;
1309 }
1310 
1311 /*
1312  * die_get_postprologue_addr - Search next address after function prologue
1313  * @entrypc_idx: entrypc index
1314  * @lines: Line records of single CU
1315  * @nr_lines: Number of @lines
1316  * @hignpc: high PC address of function
1317  * @postprologue_addr: Next address after function prologue (return value)
1318  *
1319  * Look for prologue-end marker. If there is no explicit marker, return
1320  * address of next line record or next source line.
1321  */
1322 static bool die_get_postprologue_addr(unsigned long entrypc_idx,
1323                       Dwarf_Lines *lines,
1324                       unsigned long nr_lines,
1325                       Dwarf_Addr highpc,
1326                       Dwarf_Addr *postprologue_addr)
1327 {
1328     unsigned long i;
1329     int entrypc_lno, lno;
1330     Dwarf_Line *line;
1331     Dwarf_Addr addr;
1332     bool p_end;
1333 
1334     /* entrypc_lno is actual source line number */
1335     line = dwarf_onesrcline(lines, entrypc_idx);
1336     if (dwarf_lineno(line, &entrypc_lno))
1337         return false;
1338 
1339     for (i = entrypc_idx; i < nr_lines; i++) {
1340         line = dwarf_onesrcline(lines, i);
1341 
1342         if (dwarf_lineaddr(line, &addr) ||
1343             dwarf_lineno(line, &lno)    ||
1344             dwarf_lineprologueend(line, &p_end))
1345             return false;
1346 
1347         /* highpc is exclusive. [entrypc,highpc) */
1348         if (addr >= highpc)
1349             break;
1350 
1351         /* clang supports prologue-end marker */
1352         if (p_end)
1353             break;
1354 
1355         /* Actual next line in source */
1356         if (lno != entrypc_lno)
1357             break;
1358 
1359         /*
1360          * Single source line can have multiple line records.
1361          * For Example,
1362          *     void foo() { printf("hello\n"); }
1363          * contains two line records. One points to declaration and
1364          * other points to printf() line. Variable 'lno' won't get
1365          * incremented in this case but 'i' will.
1366          */
1367         if (i != entrypc_idx)
1368             break;
1369     }
1370 
1371     dwarf_lineaddr(line, postprologue_addr);
1372     if (*postprologue_addr >= highpc)
1373         dwarf_lineaddr(dwarf_onesrcline(lines, i - 1),
1374                    postprologue_addr);
1375 
1376     return true;
1377 }
1378 
1379 /*
1380  * die_skip_prologue - Use next address after prologue as probe location
1381  * @sp_die: a subprogram DIE
1382  * @cu_die: a CU DIE
1383  * @entrypc: entrypc of the function
1384  *
1385  * Function prologue prepares stack and registers before executing function
1386  * logic. When target program is compiled without optimization, function
1387  * parameter information is only valid after prologue. When we probe entrypc
1388  * of the function, and try to record function parameter, it contains
1389  * garbage value.
1390  */
1391 void die_skip_prologue(Dwarf_Die *sp_die, Dwarf_Die *cu_die,
1392                Dwarf_Addr *entrypc)
1393 {
1394     size_t nr_lines = 0;
1395     unsigned long entrypc_idx = 0;
1396     Dwarf_Lines *lines = NULL;
1397     Dwarf_Addr postprologue_addr;
1398     Dwarf_Addr highpc;
1399 
1400     if (dwarf_highpc(sp_die, &highpc))
1401         return;
1402 
1403     if (dwarf_getsrclines(cu_die, &lines, &nr_lines))
1404         return;
1405 
1406     if (!die_search_idx(lines, nr_lines, *entrypc, &entrypc_idx))
1407         return;
1408 
1409     if (!die_get_postprologue_addr(entrypc_idx, lines, nr_lines,
1410                        highpc, &postprologue_addr))
1411         return;
1412 
1413     *entrypc = postprologue_addr;
1414 }