Fix some corners of DW_EH_PE_* handling.
authorRoland McGrath <roland@redhat.com>
Wed, 16 Jun 2010 10:04:09 +0000 (03:04 -0700)
committerRoland McGrath <roland@redhat.com>
Wed, 16 Jun 2010 10:04:09 +0000 (03:04 -0700)
libdw/ChangeLog
libdw/encoded-value.h

index 18a423e..e0e4c55 100644 (file)
@@ -1,5 +1,8 @@
 2010-06-16  Roland McGrath  <roland@redhat.com>
 
+       * encoded-value.h (read_encoded_value): Handle DW_EH_PE_indirect.
+       Don't assume DW_EH_PE_aligned refers to native address size.
+
        * cfi.c (execute_cfi): Barf on CIE initial instructions changing the
        address.
 
index 3f9b244..e118a1c 100644 (file)
@@ -1,5 +1,5 @@
 /* DW_EH_PE_* support for libdw unwinder.
-   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
@@ -136,13 +136,13 @@ read_encoded_value (const Dwarf_CFI *cache, uint8_t encoding, const uint8_t **p,
       break;
     case DW_EH_PE_aligned:
       {
-       const size_t address_size
-         = cache->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
+       const size_t size = encoded_value_size (&cache->data->d, cache->e_ident,
+                                               encoding, *p);
        size_t align = ((cache->frame_vaddr
                         + (*p - (const uint8_t *) cache->data->d.d_buf))
-                       & (address_size - 1));
+                       & (size - 1));
        if (align != 0)
-         *p += address_size - align;
+         *p += size - align;
        break;
       }
 
@@ -163,24 +163,24 @@ read_encoded_value (const Dwarf_CFI *cache, uint8_t encoding, const uint8_t **p,
 
     case DW_EH_PE_udata4:
       if (__libdw_cfi_read_address_inc (cache, p, 4, &value))
-       return false;
+       return true;
       break;
 
     case DW_EH_PE_sdata4:
       if (__libdw_cfi_read_address_inc (cache, p, 4, &value))
-       return false;
+       return true;
       value = (Dwarf_Sword) (Elf32_Sword) value; /* Sign-extend.  */
       break;
 
     case DW_EH_PE_udata8:
     case DW_EH_PE_sdata8:
       if (__libdw_cfi_read_address_inc (cache, p, 8, &value))
-       return false;
+       return true;
       break;
 
     case DW_EH_PE_absptr:
       if (__libdw_cfi_read_address_inc (cache, p, 0, &value))
-       return false;
+       return true;
       break;
 
     case DW_EH_PE_uleb128:
@@ -196,6 +196,20 @@ read_encoded_value (const Dwarf_CFI *cache, uint8_t encoding, const uint8_t **p,
     }
 
   *result += value;
+
+  if (encoding & DW_EH_PE_indirect)
+    {
+      if (unlikely (*result < cache->frame_vaddr))
+       return true;
+      *result -= cache->frame_vaddr;
+      if (unlikely (*result > (cache->data->d.d_size
+                              - encoded_value_size (NULL, cache->e_ident,
+                                                    DW_EH_PE_absptr, NULL))))
+       return true;
+      const uint8_t *ptr = cache->data->d.d_buf + *result;
+      return __libdw_cfi_read_address_inc (cache, &ptr, 0, result);
+    }
+
   return false;
 }