/* Handles simple location entries and loclists. Returns all the Locdesc's thru llbuf. Will not work properly for DWARF5 and may not work for some recent versions of gcc or llvm emitting DWARF4 with location extensions. Does not work for .debug_loc.dwo Use dwarf_get_loclist_b() and associated functions. */ int dwarf_loclist_n(Dwarf_Attribute attr, Dwarf_Locdesc *** llbuf_out, Dwarf_Signed * listlen_out, Dwarf_Error * error) { Dwarf_Debug dbg; /* Dwarf_Attribute that describes the DW_AT_location in die, if present. */ Dwarf_Attribute loc_attr = attr; /* Dwarf_Block that describes a single location expression. */ Dwarf_Block_c loc_block; /* A pointer to the current Dwarf_Locdesc read. */ Dwarf_Locdesc *locdesc = 0; Dwarf_Half form = 0; Dwarf_Addr lowpc = 0; Dwarf_Addr highpc = 0; Dwarf_Signed listlen = 0; Dwarf_Locdesc **llbuf = 0; Dwarf_CU_Context cucontext = 0; unsigned address_size = 0; int cuvstamp = 0; Dwarf_Bool is_cu = FALSE; int blkres = DW_DLV_ERROR; int setup_res = DW_DLV_ERROR; /* ***** BEGIN CODE ***** */ setup_res = _dwarf_setup_loc(attr, &dbg,&cucontext, &form, error); if (setup_res != DW_DLV_OK) { return setup_res; } cuvstamp = cucontext->cc_version_stamp; address_size = cucontext->cc_address_size; /* If this is a form_block then it's a location expression. If it's DW_FORM_data4 or DW_FORM_data8 in DWARF2 or DWARF3 (or in DWARF4 or 5 a DW_FORM_sec_offset) it's a loclist offset */ if (cuvstamp == DW_CU_VERSION5) { /* Use a newer interface. */ _dwarf_error(dbg, error, DW_DLE_LOCLIST_INTERFACE_ERROR); return (DW_DLV_ERROR); } if (((cuvstamp == DW_CU_VERSION2 || cuvstamp == DW_CU_VERSION3) && (form == DW_FORM_data4 || form == DW_FORM_data8)) || ((cuvstamp == DW_CU_VERSION4) && form == DW_FORM_sec_offset)) { setup_res = context_is_cu_not_tu(cucontext,&is_cu,error); if(setup_res != DW_DLV_OK) { return setup_res; } /* A reference to .debug_loc, with an offset in .debug_loc of a loclist */ Dwarf_Unsigned loclist_offset = 0; int off_res = DW_DLV_ERROR; int count_res = DW_DLV_ERROR; int loclist_count = 0; int lli = 0; off_res = _dwarf_get_loclist_header_start(dbg, attr, &loclist_offset, error); if (off_res != DW_DLV_OK) { return off_res; } count_res = _dwarf_get_loclist_count(dbg, loclist_offset, address_size, &loclist_count, error); listlen = loclist_count; if (count_res != DW_DLV_OK) { return count_res; } if (loclist_count == 0) { return DW_DLV_NO_ENTRY; } llbuf = (Dwarf_Locdesc **) _dwarf_get_alloc(dbg, DW_DLA_LIST, loclist_count); if (!llbuf) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } for (lli = 0; lli < loclist_count; ++lli) { int lres = 0; blkres = _dwarf_read_loc_section(dbg, &loc_block, &lowpc, &highpc, loclist_offset, address_size, error); if (blkres != DW_DLV_OK) { _dwarf_cleanup_llbuf(dbg, llbuf, lli); return (blkres); } lres = _dwarf_get_locdesc(dbg, &loc_block, address_size, cucontext->cc_length_size, cucontext->cc_version_stamp, lowpc, highpc, &locdesc, error); if (lres != DW_DLV_OK) { _dwarf_cleanup_llbuf(dbg, llbuf, lli); /* low level error already set: let it be passed back */ return lres; } llbuf[lli] = locdesc; /* Now get to next loclist entry offset. */ loclist_offset = loc_block.bl_section_offset + loc_block.bl_len; } } else { if( form == DW_FORM_exprloc) { blkres = dwarf_formexprloc(loc_attr,&loc_block.bl_len, &loc_block.bl_data,error); if(blkres != DW_DLV_OK) { return blkres; } loc_block.bl_from_loclist = 0; loc_block.bl_section_offset = (char *)loc_block.bl_data - (char *)dbg->de_debug_info.dss_data; } else { Dwarf_Block *tblock = 0; blkres = dwarf_formblock(loc_attr, &tblock, error); if (blkres != DW_DLV_OK) { return (blkres); } loc_block.bl_len = tblock->bl_len;; loc_block.bl_data = tblock->bl_data; loc_block.bl_from_loclist = tblock->bl_from_loclist; loc_block.bl_section_offset = tblock->bl_section_offset; loc_block.bl_locdesc_offset = 0; /* not relevent */ /* We copied tblock contents to the stack var, so can dealloc tblock now. Avoids leaks. */ dwarf_dealloc(dbg, tblock, DW_DLA_BLOCK); } listlen = 1; /* One by definition of a location entry. */ lowpc = 0; /* HACK */ highpc = (Dwarf_Unsigned) (-1LL); /* HACK */ /* An empty location description (block length 0) means the code generator emitted no variable, the variable was not generated, it was unused or perhaps never tested after being set. Dwarf2, section 2.4.1 In other words, it is not an error, and we don't test for block length 0 specially here. */ blkres = _dwarf_get_locdesc(dbg, &loc_block, address_size, cucontext->cc_length_size, cucontext->cc_version_stamp, lowpc, highpc, &locdesc, error); if (blkres != DW_DLV_OK) { /* low level error already set: let it be passed back */ return blkres; } llbuf = (Dwarf_Locdesc **) _dwarf_get_alloc(dbg, DW_DLA_LIST, listlen); if (!llbuf) { /* Free the locdesc we allocated but won't use. */ dwarf_dealloc(dbg, locdesc, DW_DLA_LOCDESC); _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } llbuf[0] = locdesc; } *llbuf_out = llbuf; *listlen_out = listlen; return (DW_DLV_OK); }
/* New October 2015 This interface requires the use of interface functions to get data from Dwarf_Locdesc_c. The structures are not visible to callers. */ int dwarf_get_loclist_c(Dwarf_Attribute attr, Dwarf_Loc_Head_c * ll_header_out, Dwarf_Unsigned * listlen_out, Dwarf_Error * error) { Dwarf_Debug dbg; /* Dwarf_Attribute that describes the DW_AT_location in die, if present. */ Dwarf_Attribute loc_attr = attr; /* Dwarf_Block that describes a single location expression. */ Dwarf_Block_c loc_block; Dwarf_Half form = 0; Dwarf_Addr lowpc = 0; Dwarf_Addr highpc = 0; Dwarf_Unsigned listlen = 0; Dwarf_Locdesc_c llbuf = 0; Dwarf_Loc_Head_c llhead = 0; Dwarf_CU_Context cucontext = 0; unsigned address_size = 0; int cuvstamp = 0; Dwarf_Bool is_cu = FALSE; int blkres = DW_DLV_ERROR; int setup_res = DW_DLV_ERROR; /* ***** BEGIN CODE ***** */ setup_res = _dwarf_setup_loc(attr, &dbg,&cucontext, &form, error); if (setup_res != DW_DLV_OK) { return setup_res; } cuvstamp = cucontext->cc_version_stamp; address_size = cucontext->cc_address_size; /* If this is a form_block then it's a location expression. If it's DW_FORM_data4 or DW_FORM_data8 in DWARF2 or DWARF3 (or in DWARF4 or 5 a DW_FORM_sec_offset) it's a loclist offset */ if (((cuvstamp == DW_CU_VERSION2 || cuvstamp == DW_CU_VERSION3) && (form == DW_FORM_data4 || form == DW_FORM_data8)) || ((cuvstamp == DW_CU_VERSION4 || cuvstamp == DW_CU_VERSION5) && form == DW_FORM_sec_offset)) { /* Here we have a loclist to deal with. */ setup_res = context_is_cu_not_tu(cucontext,&is_cu,error); if(setup_res != DW_DLV_OK) { return setup_res; } if (cucontext->cc_is_dwo) { /* dwo loclist. If this were a skeleton CU (ie, in the base, not dwo/dwp) then it could not have a loclist. */ /* A reference to .debug_loc.dwo, with an offset in .debug_loc.dwo of a loclist */ Dwarf_Unsigned loclist_offset = 0; int off_res = DW_DLV_ERROR; int count_res = DW_DLV_ERROR; int loclist_count = 0; Dwarf_Unsigned lli = 0; off_res = _dwarf_get_loclist_header_start(dbg, attr, &loclist_offset, error); if (off_res != DW_DLV_OK) { return off_res; } count_res = _dwarf_get_loclist_count_dwo(dbg, loclist_offset, address_size, &loclist_count, error); if (count_res != DW_DLV_OK) { return count_res; } listlen = loclist_count; if (loclist_count == 0) { return DW_DLV_NO_ENTRY; } llhead = (Dwarf_Loc_Head_c)_dwarf_get_alloc(dbg, DW_DLA_LOC_HEAD_C, 1); if (!llhead) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } listlen = loclist_count; llbuf = (Dwarf_Locdesc_c) _dwarf_get_alloc(dbg, DW_DLA_LOCDESC_C, listlen); if (!llbuf) { dwarf_loc_head_c_dealloc(llhead); _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } llhead->ll_locdesc = llbuf; llhead->ll_locdesc_count = listlen; llhead->ll_from_loclist = 2; llhead->ll_context = cucontext; llhead->ll_dbg = dbg; /* New get loc ops, DWO version */ for (lli = 0; lli < listlen; ++lli) { int lres = 0; Dwarf_Half lle_op = 0; Dwarf_Bool at_end = 0; blkres = _dwarf_read_loc_section_dwo(dbg, &loc_block, &lowpc, &highpc, &at_end, &lle_op, loclist_offset, address_size, error); if (blkres != DW_DLV_OK) { dwarf_loc_head_c_dealloc(llhead); return blkres; } /* Fills in the locdesc at index lli */ lres = _dwarf_get_locdesc_c(dbg, lli, llhead, &loc_block, address_size, cucontext->cc_length_size, cucontext->cc_version_stamp, lowpc, highpc, error); if (lres != DW_DLV_OK) { dwarf_loc_head_c_dealloc(llhead); /* low level error already set: let it be passed back */ return lres; } /* Override the syntesized lle value with the real one. */ llhead->ll_locdesc[lli].ld_lle_value = lle_op; /* Now get to next loclist entry offset. */ loclist_offset = loc_block.bl_section_offset + loc_block.bl_len; } } else { /* Non-dwo loclist. If this were a skeleton CU (ie, in the base, not dwo/dwp) then it could not have a loclist. */ /* A reference to .debug_loc, with an offset in .debug_loc of a loclist */ Dwarf_Unsigned loclist_offset = 0; int off_res = DW_DLV_ERROR; int count_res = DW_DLV_ERROR; int loclist_count = 0; Dwarf_Unsigned lli = 0; off_res = _dwarf_get_loclist_header_start(dbg, attr, &loclist_offset, error); if (off_res != DW_DLV_OK) { return off_res; } count_res = _dwarf_get_loclist_count(dbg, loclist_offset, address_size, &loclist_count, error); listlen = loclist_count; if (count_res != DW_DLV_OK) { return count_res; } if (loclist_count == 0) { return DW_DLV_NO_ENTRY; } llhead = (Dwarf_Loc_Head_c)_dwarf_get_alloc(dbg, DW_DLA_LOC_HEAD_C, 1); if (!llhead) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } listlen = loclist_count; llbuf = (Dwarf_Locdesc_c) _dwarf_get_alloc(dbg, DW_DLA_LOCDESC_C, listlen); if (!llbuf) { dwarf_loc_head_c_dealloc(llhead); _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } llhead->ll_locdesc = llbuf; llhead->ll_locdesc_count = listlen; llhead->ll_from_loclist = 1; llhead->ll_context = cucontext; llhead->ll_dbg = dbg; /* New locdesc and Loc, non-DWO, so old format */ for (lli = 0; lli < listlen; ++lli) { int lres = 0; Dwarf_Block_c c; blkres = _dwarf_read_loc_section(dbg, &c, &lowpc, &highpc, loclist_offset, address_size, error); if (blkres != DW_DLV_OK) { dwarf_loc_head_c_dealloc(llhead); return (blkres); } loc_block.bl_len = c.bl_len; loc_block.bl_data = c.bl_data; loc_block.bl_from_loclist = c.bl_from_loclist; loc_block.bl_section_offset = c.bl_section_offset; loc_block.bl_locdesc_offset = loclist_offset; /* Fills in the locdesc at index lli */ lres = _dwarf_get_locdesc_c(dbg, lli, llhead, &loc_block, address_size, cucontext->cc_length_size, cucontext->cc_version_stamp, lowpc, highpc, error); if (lres != DW_DLV_OK) { dwarf_loc_head_c_dealloc(llhead); /* low level error already set: let it be passed back */ return lres; } /* Now get to next loclist entry offset. */ loclist_offset = loc_block.bl_section_offset + loc_block.bl_len; } } } else { llhead = (Dwarf_Loc_Head_c) _dwarf_get_alloc(dbg, DW_DLA_LOC_HEAD_C, 1); if (!llhead) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } if( form == DW_FORM_exprloc) { blkres = dwarf_formexprloc(loc_attr,&loc_block.bl_len, &loc_block.bl_data,error); if(blkres != DW_DLV_OK) { dwarf_loc_head_c_dealloc(llhead); return blkres; } loc_block.bl_from_loclist = 0; loc_block.bl_section_offset = (char *)loc_block.bl_data - (char *)dbg->de_debug_info.dss_data; loc_block.bl_locdesc_offset = 0; /* not relevant */ } else { Dwarf_Block *tblock = 0; blkres = dwarf_formblock(loc_attr, &tblock, error); if (blkres != DW_DLV_OK) { dwarf_loc_head_c_dealloc(llhead); return (blkres); } loc_block.bl_len = tblock->bl_len; loc_block.bl_data = tblock->bl_data; loc_block.bl_from_loclist = tblock->bl_from_loclist; loc_block.bl_section_offset = tblock->bl_section_offset; loc_block.bl_locdesc_offset = 0; /* not relevant */ /* We copied tblock contents to the stack var, so can dealloc tblock now. Avoids leaks. */ dwarf_dealloc(dbg, tblock, DW_DLA_BLOCK); } listlen = 1; /* One by definition of a location entry. */ /* This hack ensures that the Locdesc_c is marked DW_LLE_start_end_entry */ lowpc = 0; /* HACK */ highpc = (Dwarf_Unsigned) (-1LL); /* HACK */ llbuf = (Dwarf_Locdesc_c) _dwarf_get_alloc(dbg, DW_DLA_LOCDESC_C, listlen); if (!llbuf) { dwarf_loc_head_c_dealloc(llhead); _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } llhead->ll_locdesc = llbuf; llhead->ll_locdesc = llbuf; llhead->ll_locdesc_count = listlen; llhead->ll_from_loclist = 0; llhead->ll_context = cucontext; llhead->ll_dbg = dbg; /* An empty location description (block length 0) means the code generator emitted no variable, the variable was not generated, it was unused or perhaps never tested after being set. Dwarf2, section 2.4.1 In other words, it is not an error, and we don't test for block length 0 specially here. */ /* Fills in the locdesc at index 0 */ blkres = _dwarf_get_locdesc_c(dbg, 0, /* fake locdesc is index 0 */ llhead, &loc_block, address_size, cucontext->cc_length_size, cucontext->cc_version_stamp, lowpc, highpc, error); if (blkres != DW_DLV_OK) { dwarf_loc_head_c_dealloc(llhead); /* low level error already set: let it be passed back */ return blkres; } } *ll_header_out = llhead; *listlen_out = listlen; return (DW_DLV_OK); }