Dwarf_Word operand = opcode & CFI_PRIMARY_MAX;
switch (opcode)
{
+ /* These cases move LOC, i.e. "create a new table row". */
+
case DW_CFA_advance_loc1:
operand = *program++;
case DW_CFA_advance_loc + 0 ... DW_CFA_advance_loc + CFI_PRIMARY_MAX:
loc = read_encoded_value (cache, cie->fde_encoding, &program);
break;
+ /* Now all following cases affect this row, but do not touch LOC.
+ These cases end with 'continue'. We only get out of the
+ switch block for the row-copying (LOC-moving) cases above. */
+
case DW_CFA_def_cfa:
get_uleb128 (operand, program);
get_uleb128 (offset, program);
/* Prime the rest of the Dwarf_Op so dwarf_frame_cfa can use it. */
fs->cfa_data.offset.atom = DW_OP_bregx;
fs->cfa_data.offset.offset = 0;
- break;
+ continue;
case DW_CFA_def_cfa_register:
get_uleb128 (regno, program);
cfi_assert (fs->cfa_rule == cfa_offset);
fs->cfa_val_reg = regno;
- break;
+ continue;
case DW_CFA_def_cfa_sf:
get_uleb128 (operand, program);
def_cfa_offset:
cfi_assert (fs->cfa_rule == cfa_offset);
fs->cfa_val_offset = offset;
- break;
+ continue;
case DW_CFA_def_cfa_offset_sf:
get_sleb128 (sf_offset, program);
fs->cfa_data.expr.data = (unsigned char *) program;
fs->cfa_data.expr.length = operand;
program += operand;
- break;
+ continue;
case DW_CFA_undefined:
get_uleb128 (regno, program);
register_rule (regno, undefined, 0);
- break;
+ continue;
case DW_CFA_same_value:
get_uleb128 (regno, program);
register_rule (regno, same_value, 0);
- break;
+ continue;
case DW_CFA_offset_extended:
get_uleb128 (operand, program);
offset *= cie->data_alignment_factor;
offset_extended:
register_rule (operand, offset, offset);
- break;
+ continue;
case DW_CFA_offset_extended_sf:
get_uleb128 (operand, program);
offset *= cie->data_alignment_factor;
val_offset:
register_rule (operand, val_offset, offset);
- break;
+ continue;
case DW_CFA_val_offset_sf:
get_uleb128 (operand, program);
get_uleb128 (regno, program);
get_uleb128 (operand, program);
register_rule (regno, register, operand);
- break;
+ continue;
case DW_CFA_expression:
get_uleb128 (regno, program);
cfi_assert (operand <= (Dwarf_Word) (end - program));
register_rule (regno, expression, offset);
program += operand;
- break;
+ continue;
case DW_CFA_val_expression:
get_uleb128 (regno, program);
cfi_assert (operand <= (Dwarf_Word) (end - program));
register_rule (regno, val_expression, offset);
program += operand;
- break;
+ continue;
case DW_CFA_restore_extended:
get_uleb128 (operand, program);
{
/* Special case hack to give backend abi_cfi a shorthand. */
cache->default_same_value = true;
- break;
+ continue;
}
/* This can't be used in the CIE's own initial instructions. */
fs->regs[operand] = cie->initial_state->regs[operand];
else
fs->regs[operand].rule = reg_unspecified;
- break;
+ continue;
case DW_CFA_remember_state:
{
goto out;
}
fs = copy;
- break;
+ continue;
}
case DW_CFA_restore_state:
free (fs);
fs = prev;
}
- break;
+ continue;
case DW_CFA_nop:
- break;
+ continue;
case DW_CFA_GNU_window_save:
/* This is magic shorthand used only by SPARC. It's equivalent
fs->regs[regno].rule = reg_offset;
fs->regs[regno].value = (regno - 16) * address_size;
}
- break;
+ continue;
case DW_CFA_GNU_args_size:
/* XXX is this useful for anything? */
get_uleb128 (operand, program);
- break;
+ continue;
default:
cfi_assert (false);
- break;
+ continue;
}
- if (find_pc < loc)
- /* We have just advanced past the address we're looking for.
- The state currently described is what we want to see. */
- break;
+ /* We get here only for the cases that have just moved LOC. */
+ if (find_pc >= loc)
+ /* This advance has not yet reached FIND_PC. */
+ fs->start = loc;
+ else
+ {
+ /* We have just advanced past the address we're looking for.
+ The state currently described is what we want to see. */
+ fs->end = loc;
+ break;
+ }
}
/* "The end of the instruction stream can be thought of as a
When we fall off the end of the program without an advance_loc/set_loc
that put us past FIND_PC, the final state left by the FDE program
- applies to this address (the caller ensured it was inside the FDE). */
+ applies to this address (the caller ensured it was inside the FDE).
+ This address (FDE->end) is already in FS->end as set by the caller. */
#undef register_rule
#undef cfi_assert
return DWARF_E_NOMEM;
fs->fde = fde;
+ fs->start = fde->start;
+ fs->end = fde->end;
int result = execute_cfi (cache, fde->cie, &fs,
fde->instructions, fde->instructions_end, false,
Dwarf_Addr address, Dwarf_Frame **frame)
__nonnull_attribute__ (3);
-/* 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)
- __nonnull_attribute__ (2);
-
/* Return the DWARF register number used in FRAME to denote
- the return address in FRAME's caller frame.
+ the return address in FRAME's caller frame. The remaining
+ arguments can be non-null to fill in more information.
+ Fill [*START, *END) with the PC range to which FRAME's information applies.
Fill in *SIGNALP to indicate whether this is a signal-handling frame.
If true, this is the implicit call frame that calls a signal handler.
This frame's "caller" is actually the interrupted state, not a call;
its return address is an exact PC, not a PC after a call instruction. */
-extern int dwarf_frame_return_address_register (Dwarf_Frame *frame,
- bool *signalp)
- __nonnull_attribute__ (1, 2);
+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)
+ __nonnull_attribute__ (2);
/* Deliver a DWARF expression that yields the location or value of
DWARF register number REGNO in the state described by FRAME.
/* Test program for CFI handling.
- Copyright (C) 2006 Red Hat, Inc.
+ Copyright (C) 2006, 2009 Red Hat, Inc.
This file is part of Red Hat elfutils.
Red Hat elfutils is free software; you can redistribute it and/or modify
if (result != 0)
error (EXIT_FAILURE, 0, "dwfl_addrframe: %s", dwfl_errmsg (-1));
- printf ("%#" PRIx64 ":\n", pc);
-
+ Dwarf_Addr start = pc;
+ Dwarf_Addr end = pc;
bool signalp;
- int ra_regno = dwarf_frame_return_address_register (frame, &signalp);
+ int ra_regno = dwarf_frame_info (frame, &start, &end, &signalp);
+
+ printf ("%#" PRIx64 " => [%#" PRIx64 ", %#" PRIx64 "):\n", pc, start, end);
+
if (ra_regno < 0)
printf ("\treturn address register unavailable (%s)\n",
dwarf_errmsg (0));