From 3b10ac0ade6aae156b76884421eb82985b4e9be8 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Mon, 26 Apr 2010 18:45:36 -0700 Subject: libdw: Record ill-specified CFA rule and diagnose in dwarf_frame_cfa, not immediately at decode time. --- libdw/ChangeLog | 5 +++++ libdw/cfi.c | 10 ++++++++-- libdw/cfi.h | 9 ++++++--- libdw/dwarf_frame_cfa.c | 5 +++++ 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 + * 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 (); } -- cgit v1.2.1