+2009-07-22 Roland McGrath <roland@redhat.com>
+
+ * dwarf_frame_cfa.c: Change calling convention.
+ * libdw.h: Update decl.
+
+ * dwarf_frame_register.c: Change calling/return-value convention for
+ value-only results and undefined/same_value.
+ * libdw.h: Update decl.
+
+ * dwarf_getlocation.c (__libdw_intern_expression): Take new bool
+ argument, append DW_OP_stack_value if set. Don't take NOPS argument,
+ return that value instead.
+ (getlocation): Update caller.
+ * dwarf_frame_cfa.c: Likewise.
+ * libdwP.h: Update decl.
+
2009-07-21 Roland McGrath <roland@redhat.com>
* dwarf_getsrc_file.c: Ignore a CU that just has no DW_AT_stmt_list.
#include <stdlib.h>
int
-dwarf_frame_cfa (fs, ops)
+dwarf_frame_cfa (fs, ops, nops)
Dwarf_Frame *fs;
Dwarf_Op **ops;
+ size_t *nops;
{
/* Maybe there was a previous error. */
if (fs == NULL)
return -1;
+ int result = 0;
switch (fs->cfa_rule)
{
case cfa_undefined:
*ops = NULL;
- return 0;
+ *nops = 0;
+ break;
case cfa_offset:
/* The Dwarf_Op was already fully initialized by execute_cfi. */
*ops = &fs->cfa_data.offset;
- return 1;
+ *nops = 1;
+ break;
case cfa_expr:
- {
- unsigned int address_size = (fs->cache->e_ident[EI_CLASS] == ELFCLASS32
- ? 4 : 8);
- size_t nops;
-
- /* Parse the expression into internal form. */
- int result = __libdw_intern_expression (NULL,
- fs->cache->other_byte_order,
- address_size,
- &fs->cache->expr_tree,
- &fs->cfa_data.expr,
- ops, &nops,
- IDX_debug_frame);
- return result ?: (int) nops;
- }
+ /* Parse the expression into internal form. */
+ result = __libdw_intern_expression
+ (NULL, fs->cache->other_byte_order,
+ fs->cache->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8,
+ &fs->cache->expr_tree, &fs->cfa_data.expr, false,
+ ops, nops, IDX_debug_frame);
+ break;
default:
abort ();
}
- /*NOTREACHED*/
- return -1;
+ return result;
}
dwarf_frame_register (fs, regno, ops_mem, ops, nops)
Dwarf_Frame *fs;
int regno;
- Dwarf_Op ops_mem[2];
+ Dwarf_Op ops_mem[3];
Dwarf_Op **ops;
size_t *nops;
{
return -1;
}
- int result = 0; /* A location, not a value. */
+ *ops = ops_mem;
+ *nops = 0;
if (unlikely ((size_t) regno >= fs->nregs))
goto default_rule;
/*FALLTHROUGH*/
case reg_undefined:
/* The value is known to be unavailable. */
- result = 1;
- /*FALLTHROUGH*/
+ break;
+
case reg_same_value:
same_value:
/* The location is not known here, but the caller might know it. */
*ops = NULL;
- *nops = 0;
break;
- case reg_val_offset:
- result = 1; /* A value, not a location. */
- /*FALLTHROUGH*/
case reg_offset:
- ops_mem[0] = (Dwarf_Op) { .atom = DW_OP_call_frame_cfa };
- ops_mem[1] = (Dwarf_Op) { .atom = DW_OP_plus_uconst,
- .number = reg->value };
+ case reg_val_offset:
+ ops_mem[(*nops)++] = (Dwarf_Op) { .atom = DW_OP_call_frame_cfa };
+ if (reg->value != 0)
+ ops_mem[(*nops)++] = (Dwarf_Op) { .atom = DW_OP_plus_uconst,
+ .number = reg->value };
+ if (reg->rule == reg_val_offset)
+ /* A value, not a location. */
+ ops_mem[(*nops)++] = (Dwarf_Op) { .atom = DW_OP_stack_value };
*ops = ops_mem;
- *nops = reg->value == 0 ? 1 : 2;
break;
case reg_register:
- ops_mem[0] = (Dwarf_Op) { .atom = DW_OP_regx, .number = reg->value };
- *ops = ops_mem;
- *nops = 1;
+ ops_mem[(*nops)++] = (Dwarf_Op) { .atom = DW_OP_regx,
+ .number = reg->value };
break;
case reg_val_expression:
- result = 1; /* A value, not a location. */
- /*FALLTHROUGH*/
case reg_expression:
{
unsigned int address_size = (fs->cache->e_ident[EI_CLASS] == ELFCLASS32
if (__libdw_intern_expression (NULL,
fs->cache->other_byte_order,
address_size,
- &fs->cache->expr_tree,
- &block, ops, nops,
- IDX_debug_frame) < 0)
- result = -1;
+ &fs->cache->expr_tree, &block,
+ reg->rule == reg_val_expression,
+ ops, nops, IDX_debug_frame) < 0)
+ return -1;
break;
}
}
- return result;
+ return 0;
}
internal_function
__libdw_intern_expression (Dwarf *dbg,
bool other_byte_order, unsigned int address_size,
- void **cache, const Dwarf_Block *block,
+ void **cache, const Dwarf_Block *block, bool valuep,
Dwarf_Op **llbuf, size_t *listlen, int sec_index)
{
/* Check whether we already looked at this list. */
*llbuf = (*found)->loc;
*listlen = (*found)->nloc;
+ if (valuep)
+ {
+ assert (*listlen > 1);
+ assert ((*llbuf)[*listlen - 1].atom == DW_OP_stack_value);
+ }
+
return 0;
}
goto invalid;
}
+ if (valuep)
+ {
+ struct loclist *newloc;
+ newloc = (struct loclist *) alloca (sizeof (struct loclist));
+ newloc->atom = DW_OP_stack_value;
+ newloc->number = 0;
+ newloc->number2 = 0;
+ newloc->offset = data - block->data;
+ newloc->next = loclist;
+ loclist = newloc;
+ ++n;
+ }
+
/* Allocate the array. */
Dwarf_Op *result;
if (dbg != NULL)
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);
+ cu->address_size, &cu->locs, block, false,
+ llbuf, listlen, sec_index);
}
int
extern int dwarf_frame_info (Dwarf_Frame *frame,
Dwarf_Addr *start, Dwarf_Addr *end, bool *signalp);
-/* Deliver a DWARF expression that yields the Canonical Frame Address at
- this frame state. Returns -1 for errors, or the number of operations
- stored at *OPS. That pointer can be used only as long as FRAME is alive
- and unchanged. Returns zero if the CFA cannot be determined here. */
-extern int dwarf_frame_cfa (Dwarf_Frame *frame, Dwarf_Op **ops)
+/* Return a DWARF expression that yields the Canonical Frame Address at
+ this frame state. Returns -1 for errors, or zero for success, with
+ *NOPS set to the number of operations stored at *OPS. That pointer
+ can be used only as long as FRAME is alive and unchanged. *NOPS is
+ zero if the CFA cannot be determined here. Note that if nonempty,
+ *OPS is a DWARF expression, not a location description--append
+ DW_OP_stack_value to a get a location description for the CFA. */
+extern int dwarf_frame_cfa (Dwarf_Frame *frame, Dwarf_Op **ops, size_t *nops)
__nonnull_attribute__ (2);
-/* Deliver a DWARF expression that yields the location or value of
- DWARF register number REGNO in the state described by FRAME.
+/* Deliver a DWARF location description that yields the location or
+ value of DWARF register number REGNO in the state described by FRAME.
- Returns -1 for errors, 0 if REGNO has an accessible location,
- or 1 if REGNO has only a computable value. Stores at *NOPS
- the number of operations in the array stored at *OPS.
- With return value 0, this is a DWARF location expression.
- With return value 1, this is a DWARF expression that computes the value.
+ Returns -1 for errors or zero for success, setting *NOPS to the
+ number of operations in the array stored at *OPS. Note the last
+ operation is DW_OP_stack_value if there is no mutable location but
+ only a computable value.
- Return value 1 with *NOPS zero means CFI says the caller's REGNO is
- "undefined" here, i.e. it's call-clobbered and cannot be recovered.
+ *NOPS zero with *OPS set to OPS_MEM means CFI says the caller's
+ REGNO is "undefined", i.e. it's call-clobbered and cannot be recovered.
- Return value 0 with *NOPS zero means CFI says the caller's REGNO is
- "same_value" here, i.e. this frame did not change it; ask the caller
- frame where to find it.
+ *NOPS zero with *OPS set to a null pointer means CFI says the
+ caller's REGNO is "same_value", i.e. this frame did not change it;
+ ask the caller frame where to find it.
For common simple expressions *OPS is OPS_MEM. For arbitrary DWARF
expressions in the CFI, *OPS is an internal pointer that can be used as
long as the Dwarf_CFI used to create FRAME remains alive. */
extern int dwarf_frame_register (Dwarf_Frame *frame, int regno,
- Dwarf_Op ops_mem[2],
+ Dwarf_Op ops_mem[3],
Dwarf_Op **ops, size_t *nops)
__nonnull_attribute__ (3, 4, 5);
bool other_byte_order,
unsigned int address_size,
void **cache, const Dwarf_Block *block,
+ bool valuep,
Dwarf_Op **llbuf, size_t *listlen,
int sec_index)
- __nonnull_attribute__ (4, 5, 6, 7) internal_function;
+ __nonnull_attribute__ (4, 5, 7, 8) internal_function;
/* Return error code of last failing function call. This value is kept
+2009-07-22 Roland McGrath <roland@redhat.com>
+
+ * addrcfi.c: Update dwarf_frame_{cfa,register} calling convention.
+
2009-07-08 Roland McGrath <roland@redhat.com>
* addrcfi.c: New file.
ra_regno, signalp ? " (signal frame)" : "");
Dwarf_Op *cfa_ops;
- int cfa_nops = dwarf_frame_cfa (stuff->frame, &cfa_ops);
+ size_t cfa_nops;
+ result = dwarf_frame_cfa (stuff->frame, &cfa_ops, &cfa_nops);
printf ("\tCFA ");
- print_detail (cfa_nops < 0 ? -1 : 1, cfa_ops, cfa_nops, stuff->bias);
+ print_detail (result, cfa_ops, cfa_nops, stuff->bias);
(void) dwfl_module_register_names (dwfl_addrmodule (dwfl, pc),
&print_register, stuff);