summaryrefslogtreecommitdiffstats
path: root/libdw/dwarf_getlocation.c
diff options
context:
space:
mode:
authorRoland McGrath <[email protected]>2009-06-24 17:41:40 -0700
committerRoland McGrath <[email protected]>2009-07-08 15:15:52 -0700
commit3c84db3b4b610bf636c4363abb6d3dac5ae020f9 (patch)
treee0af0c5a7f27a3f06a66353a3da9bec0bd7bd32f /libdw/dwarf_getlocation.c
parentfe8b42e6131b74829fe31d15f31349cade566a59 (diff)
CFI support: lookup by PC and translate into DWARF location per register
Diffstat (limited to 'libdw/dwarf_getlocation.c')
-rw-r--r--libdw/dwarf_getlocation.c69
1 files changed, 52 insertions, 17 deletions
diff --git a/libdw/dwarf_getlocation.c b/libdw/dwarf_getlocation.c
index 62106ce3..b036883c 100644
--- a/libdw/dwarf_getlocation.c
+++ b/libdw/dwarf_getlocation.c
@@ -163,15 +163,16 @@ check_constant_offset (Dwarf_Attribute *attr,
return 0;
}
-static int
-getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block,
- Dwarf_Op **llbuf, size_t *listlen, int sec_index)
+int
+internal_function
+__libdw_intern_expression (Dwarf *dbg,
+ bool other_byte_order, unsigned int address_size,
+ void **cache, const Dwarf_Block *block,
+ Dwarf_Op **llbuf, size_t *listlen, int sec_index)
{
- Dwarf *dbg = cu->dbg;
-
/* Check whether we already looked at this list. */
struct loc_s fake = { .addr = block->data };
- struct loc_s **found = tfind (&fake, &cu->locs, loc_compare);
+ struct loc_s **found = tfind (&fake, cache, loc_compare);
if (found != NULL)
{
/* We already saw it. */
@@ -184,6 +185,8 @@ getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block,
const unsigned char *data = block->data;
const unsigned char *const end_data = data + block->length;
+ const struct { bool other_byte_order; } bo = { other_byte_order };
+
struct loclist *loclist = NULL;
unsigned int n = 0;
/* Decode the opcodes. It is possible in some situations to have a
@@ -204,7 +207,7 @@ getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block,
case DW_OP_addr:
/* Address, depends on address size of CU. */
if (__libdw_read_address_inc (dbg, sec_index, &data,
- cu->address_size, &newloc->number))
+ address_size, &newloc->number))
return -1;
break;
@@ -269,7 +272,7 @@ getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block,
if (unlikely (data + 2 > end_data))
goto invalid;
- newloc->number = read_2ubyte_unaligned_inc (dbg, data);
+ newloc->number = read_2ubyte_unaligned_inc (&bo, data);
break;
case DW_OP_const2s:
@@ -279,14 +282,14 @@ getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block,
if (unlikely (data + 2 > end_data))
goto invalid;
- newloc->number = read_2sbyte_unaligned_inc (dbg, data);
+ newloc->number = read_2sbyte_unaligned_inc (&bo, data);
break;
case DW_OP_const4u:
if (unlikely (data + 4 > end_data))
goto invalid;
- newloc->number = read_4ubyte_unaligned_inc (dbg, data);
+ newloc->number = read_4ubyte_unaligned_inc (&bo, data);
break;
case DW_OP_const4s:
@@ -294,21 +297,21 @@ getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block,
if (unlikely (data + 4 > end_data))
goto invalid;
- newloc->number = read_4sbyte_unaligned_inc (dbg, data);
+ newloc->number = read_4sbyte_unaligned_inc (&bo, data);
break;
case DW_OP_const8u:
if (unlikely (data + 8 > end_data))
goto invalid;
- newloc->number = read_8ubyte_unaligned_inc (dbg, data);
+ newloc->number = read_8ubyte_unaligned_inc (&bo, data);
break;
case DW_OP_const8s:
if (unlikely (data + 8 > end_data))
goto invalid;
- newloc->number = read_8sbyte_unaligned_inc (dbg, data);
+ newloc->number = read_8sbyte_unaligned_inc (&bo, data);
break;
case DW_OP_constu:
@@ -346,7 +349,19 @@ getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block,
}
/* Allocate the array. */
- Dwarf_Op *result = libdw_alloc (dbg, Dwarf_Op, sizeof (Dwarf_Op), n);
+ Dwarf_Op *result;
+ if (dbg != NULL)
+ result = libdw_alloc (dbg, Dwarf_Op, sizeof (Dwarf_Op), n);
+ else
+ {
+ result = malloc (sizeof *result * n);
+ if (result == NULL)
+ {
+ nomem:
+ __libdw_seterrno (DWARF_E_NOMEM);
+ return -1;
+ }
+ }
/* Store the result. */
*llbuf = result;
@@ -368,17 +383,37 @@ getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block,
/* Insert a record in the search tree so that we can find it again
later. */
- struct loc_s *newp = libdw_alloc (dbg, struct loc_s, sizeof (struct loc_s),
- 1);
+ struct loc_s *newp;
+ if (dbg != NULL)
+ newp = libdw_alloc (dbg, struct loc_s, sizeof (struct loc_s), 1);
+ else
+ {
+ newp = malloc (sizeof *newp);
+ if (newp == NULL)
+ {
+ free (result);
+ goto nomem;
+ }
+ }
+
newp->addr = block->data;
newp->loc = result;
newp->nloc = *listlen;
- (void) tsearch (newp, &cu->locs, loc_compare);
+ (void) tsearch (newp, cache, loc_compare);
/* We did it. */
return 0;
}
+static int
+getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block,
+ Dwarf_Op **llbuf, size_t *listlen, int sec_index)
+{
+ return __libdw_intern_expression (cu->dbg, cu->dbg->other_byte_order,
+ cu->address_size, &cu->locs,
+ block, llbuf, listlen, sec_index);
+}
+
int
dwarf_getlocation (attr, llbuf, listlen)
Dwarf_Attribute *attr;