summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2010-04-26 18:45:36 -0700
committerRoland McGrath <roland@redhat.com>2010-04-26 18:45:36 -0700
commit3b10ac0ade6aae156b76884421eb82985b4e9be8 (patch)
tree6ddc0396406fca1c03c6676f7c1fb4c41ff5273e
parentd17f9de52545417d7fec051b8e1b144234956021 (diff)
downloadelfutils-3b10ac0ade6aae156b76884421eb82985b4e9be8.tar.gz
libdw: Record ill-specified CFA rule and diagnose in dwarf_frame_cfa, not immediately at decode time.
-rw-r--r--libdw/ChangeLog5
-rw-r--r--libdw/cfi.c10
-rw-r--r--libdw/cfi.h9
-rw-r--r--libdw/dwarf_frame_cfa.c5
4 files changed, 24 insertions, 5 deletions
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 50fba721..a6e84572 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,5 +1,10 @@
2010-04-26 Roland McGrath <roland@redhat.com>
+ * cfi.h (struct Dwarf_Frame_s): Add cfa_invalid alternative in cfa_rule.
+ * cfi.c (execute_cfi): Set that instead of doing cfi_assert for
+ DW_CFA_def_cfa_{offset*,register} when a non-offset rule is in force.
+ * dwarf_frame_cfa.c (dwarf_frame_cfa): Handle cfa_invalid.
+
* dwarf_getlocation.c (__libdw_intern_expression): Take new arg CFAP.
Prepend DW_OP_call_frame_cfa if true.
(getlocation): Update caller.
diff --git a/libdw/cfi.c b/libdw/cfi.c
index 5936659a..3cb378b6 100644
--- a/libdw/cfi.c
+++ b/libdw/cfi.c
@@ -117,6 +117,12 @@ execute_cfi (Dwarf_CFI *cache,
return true;
}
+ inline void require_cfa_offset (void)
+ {
+ if (unlikely (fs->cfa_rule != cfa_offset))
+ fs->cfa_rule = cfa_invalid;
+ }
+
#define register_rule(regno, r_rule, r_value) do { \
if (unlikely (! enough_registers (regno))) \
goto out; \
@@ -177,7 +183,7 @@ execute_cfi (Dwarf_CFI *cache,
case DW_CFA_def_cfa_register:
get_uleb128 (regno, program);
- cfi_assert (fs->cfa_rule == cfa_offset);
+ require_cfa_offset ();
fs->cfa_val_reg = regno;
continue;
@@ -190,7 +196,7 @@ execute_cfi (Dwarf_CFI *cache,
case DW_CFA_def_cfa_offset:
get_uleb128 (offset, program);
def_cfa_offset:
- cfi_assert (fs->cfa_rule == cfa_offset);
+ require_cfa_offset ();
fs->cfa_val_offset = offset;
continue;
diff --git a/libdw/cfi.h b/libdw/cfi.h
index 64f3f157..e04e76dd 100644
--- a/libdw/cfi.h
+++ b/libdw/cfi.h
@@ -1,5 +1,5 @@
/* Internal definitions for libdw CFI interpreter.
- Copyright (C) 2009 Red Hat, Inc.
+ Copyright (C) 2009-2010 Red Hat, Inc.
This file is part of Red Hat elfutils.
Red Hat elfutils is free software; you can redistribute it and/or modify
@@ -191,8 +191,11 @@ struct Dwarf_Frame_s
which has the return_address_register and signal_frame flag. */
struct dwarf_fde *fde;
- /* The CFA is unknown, is R+N, or is computed by a DWARF expression. */
- enum { cfa_undefined, cfa_offset, cfa_expr } cfa_rule;
+ /* The CFA is unknown, is R+N, or is computed by a DWARF expression.
+ A bogon in the CFI can indicate an invalid/incalculable rule.
+ We store that as cfa_invalid rather than barfing when processing it,
+ so callers can ignore the bogon unless they really need that CFA. */
+ enum { cfa_undefined, cfa_offset, cfa_expr, cfa_invalid } cfa_rule;
union
{
Dwarf_Op offset;
diff --git a/libdw/dwarf_frame_cfa.c b/libdw/dwarf_frame_cfa.c
index 03c5fbd2..0ba26b2f 100644
--- a/libdw/dwarf_frame_cfa.c
+++ b/libdw/dwarf_frame_cfa.c
@@ -88,6 +88,11 @@ dwarf_frame_cfa (fs, ops, nops)
ops, nops, IDX_debug_frame);
break;
+ case cfa_invalid:
+ __libdw_seterrno (DWARF_E_INVALID_CFI);
+ result = -1;
+ break;
+
default:
abort ();
}