12de3b87aSKai Wang /*-
2*cf781b2eSEd Maste * Copyright (c) 2009,2014 Kai Wang
32de3b87aSKai Wang * All rights reserved.
42de3b87aSKai Wang *
52de3b87aSKai Wang * Redistribution and use in source and binary forms, with or without
62de3b87aSKai Wang * modification, are permitted provided that the following conditions
72de3b87aSKai Wang * are met:
82de3b87aSKai Wang * 1. Redistributions of source code must retain the above copyright
92de3b87aSKai Wang * notice, this list of conditions and the following disclaimer.
102de3b87aSKai Wang * 2. Redistributions in binary form must reproduce the above copyright
112de3b87aSKai Wang * notice, this list of conditions and the following disclaimer in the
122de3b87aSKai Wang * documentation and/or other materials provided with the distribution.
132de3b87aSKai Wang *
142de3b87aSKai Wang * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
152de3b87aSKai Wang * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
162de3b87aSKai Wang * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
172de3b87aSKai Wang * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
182de3b87aSKai Wang * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
192de3b87aSKai Wang * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
202de3b87aSKai Wang * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
212de3b87aSKai Wang * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
222de3b87aSKai Wang * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
232de3b87aSKai Wang * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
242de3b87aSKai Wang * SUCH DAMAGE.
252de3b87aSKai Wang */
262de3b87aSKai Wang
272de3b87aSKai Wang #include "_libdwarf.h"
282de3b87aSKai Wang
29*cf781b2eSEd Maste ELFTC_VCSID("$Id: dwarf_loclist.c 3066 2014-06-06 19:36:06Z kaiwang27 $");
30*cf781b2eSEd Maste
31*cf781b2eSEd Maste static int
copy_locdesc(Dwarf_Debug dbg,Dwarf_Locdesc * dst,Dwarf_Locdesc * src,Dwarf_Error * error)32*cf781b2eSEd Maste copy_locdesc(Dwarf_Debug dbg, Dwarf_Locdesc *dst, Dwarf_Locdesc *src,
33*cf781b2eSEd Maste Dwarf_Error *error)
34*cf781b2eSEd Maste {
35*cf781b2eSEd Maste
36*cf781b2eSEd Maste assert(src != NULL && dst != NULL);
37*cf781b2eSEd Maste
38*cf781b2eSEd Maste dst->ld_lopc = src->ld_lopc;
39*cf781b2eSEd Maste dst->ld_hipc = src->ld_hipc;
40*cf781b2eSEd Maste dst->ld_cents = src->ld_cents;
41*cf781b2eSEd Maste
42*cf781b2eSEd Maste if (dst->ld_cents > 0) {
43*cf781b2eSEd Maste dst->ld_s = calloc(dst->ld_cents, sizeof(Dwarf_Loc));
44*cf781b2eSEd Maste if (dst->ld_s == NULL) {
45*cf781b2eSEd Maste DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
46*cf781b2eSEd Maste return (DW_DLE_MEMORY);
47*cf781b2eSEd Maste }
48*cf781b2eSEd Maste memcpy(dst->ld_s, src->ld_s, src->ld_cents *
49*cf781b2eSEd Maste sizeof(Dwarf_Loc));
50*cf781b2eSEd Maste } else
51*cf781b2eSEd Maste dst->ld_s = NULL;
52*cf781b2eSEd Maste
53*cf781b2eSEd Maste return (DW_DLE_NONE);
54*cf781b2eSEd Maste }
552de3b87aSKai Wang
562de3b87aSKai Wang int
dwarf_loclist_n(Dwarf_Attribute at,Dwarf_Locdesc *** llbuf,Dwarf_Signed * listlen,Dwarf_Error * error)572de3b87aSKai Wang dwarf_loclist_n(Dwarf_Attribute at, Dwarf_Locdesc ***llbuf,
582de3b87aSKai Wang Dwarf_Signed *listlen, Dwarf_Error *error)
592de3b87aSKai Wang {
602de3b87aSKai Wang Dwarf_Debug dbg;
612de3b87aSKai Wang int ret;
622de3b87aSKai Wang
632de3b87aSKai Wang dbg = at != NULL ? at->at_die->die_dbg : NULL;
642de3b87aSKai Wang
652de3b87aSKai Wang if (at == NULL || llbuf == NULL || listlen == NULL) {
662de3b87aSKai Wang DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
672de3b87aSKai Wang return (DW_DLV_ERROR);
682de3b87aSKai Wang }
692de3b87aSKai Wang
702de3b87aSKai Wang switch (at->at_attrib) {
712de3b87aSKai Wang case DW_AT_location:
722de3b87aSKai Wang case DW_AT_string_length:
732de3b87aSKai Wang case DW_AT_return_addr:
742de3b87aSKai Wang case DW_AT_data_member_location:
752de3b87aSKai Wang case DW_AT_frame_base:
762de3b87aSKai Wang case DW_AT_segment:
772de3b87aSKai Wang case DW_AT_static_link:
782de3b87aSKai Wang case DW_AT_use_location:
792de3b87aSKai Wang case DW_AT_vtable_elem_location:
802de3b87aSKai Wang switch (at->at_form) {
812de3b87aSKai Wang case DW_FORM_data4:
822de3b87aSKai Wang case DW_FORM_data8:
83bc5fce8dSKai Wang /*
84bc5fce8dSKai Wang * DW_FORM_data[48] can not be used as section offset
85bc5fce8dSKai Wang * since DWARF4. For DWARF[23], the application needs
86bc5fce8dSKai Wang * to determine if DW_FORM_data[48] is representing
87bc5fce8dSKai Wang * a constant or a section offset.
88bc5fce8dSKai Wang */
89bc5fce8dSKai Wang if (at->at_die->die_cu->cu_version >= 4) {
90bc5fce8dSKai Wang DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
91bc5fce8dSKai Wang return (DW_DLV_NO_ENTRY);
92bc5fce8dSKai Wang }
93bc5fce8dSKai Wang /* FALLTHROUGH */
94bc5fce8dSKai Wang case DW_FORM_sec_offset:
95bc5fce8dSKai Wang ret = _dwarf_loclist_find(dbg, at->at_die->die_cu,
96*cf781b2eSEd Maste at->u[0].u64, llbuf, listlen, NULL, error);
972de3b87aSKai Wang if (ret == DW_DLE_NO_ENTRY) {
982de3b87aSKai Wang DWARF_SET_ERROR(dbg, error, ret);
992de3b87aSKai Wang return (DW_DLV_NO_ENTRY);
1002de3b87aSKai Wang }
1012de3b87aSKai Wang if (ret != DW_DLE_NONE)
1022de3b87aSKai Wang return (DW_DLV_ERROR);
1032de3b87aSKai Wang return (DW_DLV_OK);
1042de3b87aSKai Wang case DW_FORM_block:
1052de3b87aSKai Wang case DW_FORM_block1:
1062de3b87aSKai Wang case DW_FORM_block2:
1072de3b87aSKai Wang case DW_FORM_block4:
108*cf781b2eSEd Maste case DW_FORM_exprloc:
1092de3b87aSKai Wang if (at->at_ld == NULL) {
1102de3b87aSKai Wang ret = _dwarf_loc_add(at->at_die, at, error);
1112de3b87aSKai Wang if (ret != DW_DLE_NONE)
1122de3b87aSKai Wang return (DW_DLV_ERROR);
1132de3b87aSKai Wang }
114*cf781b2eSEd Maste *llbuf = calloc(1, sizeof(Dwarf_Locdesc *));
115*cf781b2eSEd Maste if (*llbuf == NULL) {
116*cf781b2eSEd Maste DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
117*cf781b2eSEd Maste return (DW_DLV_ERROR);
118*cf781b2eSEd Maste }
119*cf781b2eSEd Maste (*llbuf)[0] = calloc(1, sizeof(Dwarf_Locdesc));
120*cf781b2eSEd Maste if ((*llbuf)[0] == NULL) {
121*cf781b2eSEd Maste free(*llbuf);
122*cf781b2eSEd Maste DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
123*cf781b2eSEd Maste return (DW_DLV_ERROR);
124*cf781b2eSEd Maste }
125*cf781b2eSEd Maste if (copy_locdesc(dbg, (*llbuf)[0], at->at_ld, error) !=
126*cf781b2eSEd Maste DW_DLE_NONE) {
127*cf781b2eSEd Maste free((*llbuf)[0]);
128*cf781b2eSEd Maste free(*llbuf);
129*cf781b2eSEd Maste return (DW_DLV_ERROR);
130*cf781b2eSEd Maste }
1312de3b87aSKai Wang *listlen = 1;
1322de3b87aSKai Wang return (DW_DLV_OK);
1332de3b87aSKai Wang default:
1342de3b87aSKai Wang /* Malformed Attr? */
1352de3b87aSKai Wang DWARF_SET_ERROR(dbg, error, DW_DLE_ATTR_FORM_BAD);
1362de3b87aSKai Wang return (DW_DLV_NO_ENTRY);
1372de3b87aSKai Wang }
1382de3b87aSKai Wang default:
1392de3b87aSKai Wang /* Wrong attr supplied. */
1402de3b87aSKai Wang DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
1412de3b87aSKai Wang return (DW_DLV_ERROR);
1422de3b87aSKai Wang }
1432de3b87aSKai Wang }
1442de3b87aSKai Wang
1452de3b87aSKai Wang int
dwarf_loclist(Dwarf_Attribute at,Dwarf_Locdesc ** llbuf,Dwarf_Signed * listlen,Dwarf_Error * error)1462de3b87aSKai Wang dwarf_loclist(Dwarf_Attribute at, Dwarf_Locdesc **llbuf,
1472de3b87aSKai Wang Dwarf_Signed *listlen, Dwarf_Error *error)
1482de3b87aSKai Wang {
149*cf781b2eSEd Maste Dwarf_Locdesc **_llbuf;
150*cf781b2eSEd Maste int i, ret;
1512de3b87aSKai Wang
152*cf781b2eSEd Maste ret = dwarf_loclist_n(at, &_llbuf, listlen, error);
153*cf781b2eSEd Maste if (ret != DW_DLV_OK)
154*cf781b2eSEd Maste return (ret);
1552de3b87aSKai Wang
156*cf781b2eSEd Maste /* Only return the first location description of the list. */
157*cf781b2eSEd Maste *llbuf = _llbuf[0];
1582de3b87aSKai Wang
159*cf781b2eSEd Maste /* Free the rest of the list. */
160*cf781b2eSEd Maste for (i = 1; i < *listlen; i++) {
161*cf781b2eSEd Maste if (_llbuf[i]->ld_s)
162*cf781b2eSEd Maste free(_llbuf[i]->ld_s);
163*cf781b2eSEd Maste free(_llbuf[i]);
164bc5fce8dSKai Wang }
165*cf781b2eSEd Maste free(_llbuf);
166*cf781b2eSEd Maste
1672de3b87aSKai Wang *listlen = 1;
168*cf781b2eSEd Maste
1692de3b87aSKai Wang return (DW_DLV_OK);
1702de3b87aSKai Wang }
1712de3b87aSKai Wang
1722de3b87aSKai Wang int
dwarf_get_loclist_entry(Dwarf_Debug dbg,Dwarf_Unsigned offset,Dwarf_Addr * hipc,Dwarf_Addr * lopc,Dwarf_Ptr * data,Dwarf_Unsigned * entry_len,Dwarf_Unsigned * next_entry,Dwarf_Error * error)1732de3b87aSKai Wang dwarf_get_loclist_entry(Dwarf_Debug dbg, Dwarf_Unsigned offset,
1742de3b87aSKai Wang Dwarf_Addr *hipc, Dwarf_Addr *lopc, Dwarf_Ptr *data,
1752de3b87aSKai Wang Dwarf_Unsigned *entry_len, Dwarf_Unsigned *next_entry,
1762de3b87aSKai Wang Dwarf_Error *error)
1772de3b87aSKai Wang {
178*cf781b2eSEd Maste Dwarf_Locdesc *ld, **llbuf;
1792de3b87aSKai Wang Dwarf_Section *ds;
180*cf781b2eSEd Maste Dwarf_Signed listlen;
1812de3b87aSKai Wang int i, ret;
1822de3b87aSKai Wang
183*cf781b2eSEd Maste /*
184*cf781b2eSEd Maste * Note that this API sometimes will not work correctly because
185*cf781b2eSEd Maste * it assumes that all units have the same pointer size and offset
186*cf781b2eSEd Maste * size.
187*cf781b2eSEd Maste */
188*cf781b2eSEd Maste
1892de3b87aSKai Wang if (dbg == NULL || hipc == NULL || lopc == NULL || data == NULL ||
1902de3b87aSKai Wang entry_len == NULL || next_entry == NULL) {
1912de3b87aSKai Wang DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
1922de3b87aSKai Wang return (DW_DLV_ERROR);
1932de3b87aSKai Wang }
1942de3b87aSKai Wang
195*cf781b2eSEd Maste ret = _dwarf_loclist_find(dbg, STAILQ_FIRST(&dbg->dbg_cu), offset,
196*cf781b2eSEd Maste &llbuf, &listlen, entry_len, error);
1972de3b87aSKai Wang if (ret == DW_DLE_NO_ENTRY) {
1982de3b87aSKai Wang DWARF_SET_ERROR(dbg, error, DW_DLV_NO_ENTRY);
1992de3b87aSKai Wang return (DW_DLV_NO_ENTRY);
2002de3b87aSKai Wang } else if (ret != DW_DLE_NONE)
2012de3b87aSKai Wang return (DW_DLV_ERROR);
2022de3b87aSKai Wang
2032de3b87aSKai Wang *hipc = *lopc = 0;
204*cf781b2eSEd Maste for (i = 0; i < listlen; i++) {
205*cf781b2eSEd Maste ld = llbuf[i];
2062de3b87aSKai Wang if (i == 0) {
2072de3b87aSKai Wang *hipc = ld->ld_hipc;
2082de3b87aSKai Wang *lopc = ld->ld_lopc;
2092de3b87aSKai Wang } else {
2102de3b87aSKai Wang if (ld->ld_lopc < *lopc)
2112de3b87aSKai Wang *lopc = ld->ld_lopc;
2122de3b87aSKai Wang if (ld->ld_hipc > *hipc)
2132de3b87aSKai Wang *hipc = ld->ld_hipc;
2142de3b87aSKai Wang }
2152de3b87aSKai Wang }
2162de3b87aSKai Wang
2172de3b87aSKai Wang ds = _dwarf_find_section(dbg, ".debug_loc");
2182de3b87aSKai Wang assert(ds != NULL);
219*cf781b2eSEd Maste *data = (uint8_t *) ds->ds_data + offset;
220*cf781b2eSEd Maste *next_entry = offset + *entry_len;
2212de3b87aSKai Wang
2222de3b87aSKai Wang return (DW_DLV_OK);
2232de3b87aSKai Wang }
2242de3b87aSKai Wang
2252de3b87aSKai Wang int
dwarf_loclist_from_expr(Dwarf_Debug dbg,Dwarf_Ptr bytes_in,Dwarf_Unsigned bytes_len,Dwarf_Locdesc ** llbuf,Dwarf_Signed * listlen,Dwarf_Error * error)2262de3b87aSKai Wang dwarf_loclist_from_expr(Dwarf_Debug dbg, Dwarf_Ptr bytes_in,
2272de3b87aSKai Wang Dwarf_Unsigned bytes_len, Dwarf_Locdesc **llbuf, Dwarf_Signed *listlen,
2282de3b87aSKai Wang Dwarf_Error *error)
2292de3b87aSKai Wang {
2302de3b87aSKai Wang
231*cf781b2eSEd Maste return (dwarf_loclist_from_expr_a(dbg, bytes_in, bytes_len,
232*cf781b2eSEd Maste dbg->dbg_pointer_size, llbuf, listlen, error));
2332de3b87aSKai Wang }
2342de3b87aSKai Wang
2352de3b87aSKai Wang int
dwarf_loclist_from_expr_a(Dwarf_Debug dbg,Dwarf_Ptr bytes_in,Dwarf_Unsigned bytes_len,Dwarf_Half addr_size,Dwarf_Locdesc ** llbuf,Dwarf_Signed * listlen,Dwarf_Error * error)2362de3b87aSKai Wang dwarf_loclist_from_expr_a(Dwarf_Debug dbg, Dwarf_Ptr bytes_in,
2372de3b87aSKai Wang Dwarf_Unsigned bytes_len, Dwarf_Half addr_size, Dwarf_Locdesc **llbuf,
2382de3b87aSKai Wang Dwarf_Signed *listlen, Dwarf_Error *error)
2392de3b87aSKai Wang {
240*cf781b2eSEd Maste Dwarf_Half offset_size;
241*cf781b2eSEd Maste Dwarf_Small version;
242*cf781b2eSEd Maste
243*cf781b2eSEd Maste /*
244*cf781b2eSEd Maste * Obtain offset size and DWARF version from the current
245*cf781b2eSEd Maste * Compilation Unit or Type Unit. These values are needed
246*cf781b2eSEd Maste * for correctly parsing DW_OP_GNU_implicit_pointer operator.
247*cf781b2eSEd Maste *
248*cf781b2eSEd Maste * Note that dwarf_loclist_from_expr_b() should be used instead
249*cf781b2eSEd Maste * if the application knows correct values for offset size
250*cf781b2eSEd Maste * and DWARF version.
251*cf781b2eSEd Maste */
252*cf781b2eSEd Maste if (dbg->dbg_cu_current) {
253*cf781b2eSEd Maste offset_size = dbg->dbg_cu_current->cu_length_size == 4 ? 4 : 8;
254*cf781b2eSEd Maste version = dbg->dbg_cu_current->cu_version;
255*cf781b2eSEd Maste } else if (dbg->dbg_tu_current) {
256*cf781b2eSEd Maste offset_size = dbg->dbg_tu_current->cu_length_size == 4 ? 4 : 8;
257*cf781b2eSEd Maste version = dbg->dbg_tu_current->cu_version;
258*cf781b2eSEd Maste } else {
259*cf781b2eSEd Maste /* Default values if no CU/TU context. */
260*cf781b2eSEd Maste offset_size = 4;
261*cf781b2eSEd Maste version = 2; /* DWARF2 */
262*cf781b2eSEd Maste }
263*cf781b2eSEd Maste
264*cf781b2eSEd Maste return (dwarf_loclist_from_expr_b(dbg, bytes_in, bytes_len, addr_size,
265*cf781b2eSEd Maste offset_size, version, llbuf, listlen, error));
266*cf781b2eSEd Maste }
267*cf781b2eSEd Maste
268*cf781b2eSEd Maste int
dwarf_loclist_from_expr_b(Dwarf_Debug dbg,Dwarf_Ptr bytes_in,Dwarf_Unsigned bytes_len,Dwarf_Half addr_size,Dwarf_Half offset_size,Dwarf_Small version,Dwarf_Locdesc ** llbuf,Dwarf_Signed * listlen,Dwarf_Error * error)269*cf781b2eSEd Maste dwarf_loclist_from_expr_b(Dwarf_Debug dbg, Dwarf_Ptr bytes_in,
270*cf781b2eSEd Maste Dwarf_Unsigned bytes_len, Dwarf_Half addr_size, Dwarf_Half offset_size,
271*cf781b2eSEd Maste Dwarf_Small version, Dwarf_Locdesc **llbuf, Dwarf_Signed *listlen,
272*cf781b2eSEd Maste Dwarf_Error *error)
273*cf781b2eSEd Maste {
2742de3b87aSKai Wang Dwarf_Locdesc *ld;
2752de3b87aSKai Wang int ret;
2762de3b87aSKai Wang
2772de3b87aSKai Wang if (dbg == NULL || bytes_in == NULL || bytes_len == 0 ||
2782de3b87aSKai Wang llbuf == NULL || listlen == NULL) {
2792de3b87aSKai Wang DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
2802de3b87aSKai Wang return (DW_DLV_ERROR);
2812de3b87aSKai Wang }
2822de3b87aSKai Wang
2832de3b87aSKai Wang if (addr_size != 4 && addr_size != 8) {
2842de3b87aSKai Wang DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
2852de3b87aSKai Wang return (DW_DLV_ERROR);
2862de3b87aSKai Wang }
2872de3b87aSKai Wang
288*cf781b2eSEd Maste if (offset_size != 4 && offset_size != 8) {
289*cf781b2eSEd Maste DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
290*cf781b2eSEd Maste return (DW_DLV_ERROR);
291*cf781b2eSEd Maste }
292*cf781b2eSEd Maste
2932de3b87aSKai Wang ret = _dwarf_loc_fill_locexpr(dbg, &ld, bytes_in, bytes_len, addr_size,
294*cf781b2eSEd Maste offset_size, version, error);
2952de3b87aSKai Wang if (ret != DW_DLE_NONE)
2962de3b87aSKai Wang return (DW_DLV_ERROR);
2972de3b87aSKai Wang
2982de3b87aSKai Wang *llbuf = ld;
2992de3b87aSKai Wang *listlen = 1;
3002de3b87aSKai Wang
3012de3b87aSKai Wang return (DW_DLV_OK);
3022de3b87aSKai Wang }
303