Fix DW_OP_call_ref operand handling.
authorRoland McGrath <roland@redhat.com>
Sat, 8 May 2010 10:22:59 +0000 (03:22 -0700)
committerRoland McGrath <roland@redhat.com>
Sat, 8 May 2010 10:22:59 +0000 (03:22 -0700)
libdw/ChangeLog
libdw/dwarf_frame_cfa.c
libdw/dwarf_frame_register.c
libdw/dwarf_getlocation.c
libdw/libdwP.h
src/ChangeLog
src/readelf.c

index a6e8457..66e774a 100644 (file)
@@ -1,3 +1,12 @@
+2010-05-08  Roland McGrath  <roland@redhat.com>
+
+       * dwarf_getlocation.c (__libdw_intern_expression): Take new argument
+       REF_SIZE.  Use that to handle DW_OP_call_ref correctly.
+       (getlocation): Update caller.
+       * dwarf_frame_cfa.c (dwarf_frame_cfa): Likewise.
+       * dwarf_frame_register.c (dwarf_frame_register): Likewise.
+       * libdwP.h: Update decl.
+
 2010-04-26  Roland McGrath  <roland@redhat.com>
 
        * cfi.h (struct Dwarf_Frame_s): Add cfa_invalid alternative in cfa_rule.
index 0ba26b2..2f3268a 100644 (file)
@@ -1,5 +1,5 @@
 /* Get CFA expression for frame.
-   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
@@ -83,7 +83,7 @@ dwarf_frame_cfa (fs, ops, 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->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8, 4,
         &fs->cache->expr_tree, &fs->cfa_data.expr, false, false,
         ops, nops, IDX_debug_frame);
       break;
index e42b76b..ae0db02 100644 (file)
@@ -129,7 +129,7 @@ dwarf_frame_register (fs, regno, ops_mem, ops, nops)
        /* Parse the expression into internal form.  */
        if (__libdw_intern_expression (NULL,
                                       fs->cache->other_byte_order,
-                                      address_size,
+                                      address_size, 4,
                                       &fs->cache->expr_tree, &block,
                                       true, reg->rule == reg_val_expression,
                                       ops, nops, IDX_debug_frame) < 0)
index f362fe2..ede8c3c 100644 (file)
@@ -219,8 +219,8 @@ check_constant_offset (Dwarf_Attribute *attr,
 
 int
 internal_function
-__libdw_intern_expression (Dwarf *dbg,
-                          bool other_byte_order, unsigned int address_size,
+__libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
+                          unsigned int address_size, unsigned int ref_size,
                           void **cache, const Dwarf_Block *block,
                           bool cfap, bool valuep,
                           Dwarf_Op **llbuf, size_t *listlen, int sec_index)
@@ -272,6 +272,13 @@ __libdw_intern_expression (Dwarf *dbg,
            return -1;
          break;
 
+       case DW_OP_call_ref:
+         /* DW_FORM_ref_addr, depends on offset size of CU.  */
+         if (__libdw_read_offset_inc (dbg, sec_index, &data, ref_size,
+                                      &newloc->number, IDX_debug_info, 0))
+           return -1;
+         break;
+
        case DW_OP_deref:
        case DW_OP_dup:
        case DW_OP_drop:
@@ -303,7 +310,6 @@ __libdw_intern_expression (Dwarf *dbg,
        case DW_OP_reg0 ... DW_OP_reg31:
        case DW_OP_nop:
        case DW_OP_push_object_address:
-       case DW_OP_call_ref:
        case DW_OP_call_frame_cfa:
        case DW_OP_form_tls_address:
        case DW_OP_GNU_push_tls_address:
@@ -521,7 +527,10 @@ getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block,
             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,
+                                   cu->address_size, (cu->version == 2
+                                                      ? cu->address_size
+                                                      : cu->offset_size),
+                                   &cu->locs, block,
                                    false, false,
                                    llbuf, listlen, sec_index);
 }
index 44beac6..b3402d8 100644 (file)
@@ -432,11 +432,12 @@ extern int __libdw_visit_scopes (unsigned int depth,
 extern int __libdw_intern_expression (Dwarf *dbg,
                                      bool other_byte_order,
                                      unsigned int address_size,
+                                     unsigned int ref_size,
                                      void **cache, const Dwarf_Block *block,
                                      bool cfap, bool valuep,
                                      Dwarf_Op **llbuf, size_t *listlen,
                                      int sec_index)
-  __nonnull_attribute__ (4, 5, 8, 9) internal_function;
+  __nonnull_attribute__ (5, 6, 9, 10) internal_function;
 
 
 /* Return error code of last failing function call.  This value is kept
index 5341542..0a81407 100644 (file)
@@ -1,3 +1,12 @@
+2010-05-08  Roland McGrath  <roland@redhat.com>
+
+       * readelf.c (print_ops): Take new arg OFFSET_SIZE.
+       Use that for DW_OP_call_ref, not ADDRSIZE.
+       (print_cfa_program): Update caller.
+       (struct attrcb_args): Add offset_size field.
+       (attr_callback): Use it for print_ops call.
+       (print_debug_info_section): Initialize it.
+
 2010-04-14  Roland McGrath  <roland@redhat.com>
 
        * readelf.c (handle_core_item): Fix bitmask printing.
index 5255860..243337a 100644 (file)
@@ -3774,7 +3774,8 @@ print_block (size_t n, const void *block)
 
 static void
 print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
-          unsigned int addrsize, Dwarf_Word len, const unsigned char *data)
+          unsigned int addrsize, unsigned int offset_size,
+          Dwarf_Word len, const unsigned char *data)
 {
   static const char *const known[] =
     {
@@ -3949,7 +3950,6 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
 
       switch (op)
        {
-       case DW_OP_call_ref:
        case DW_OP_addr:;
          /* Address operand.  */
          Dwarf_Word addr;
@@ -3964,18 +3964,31 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
          data += addrsize;
          len -= addrsize;
 
-         if (op == DW_OP_addr)
+         char *a = format_dwarf_addr (dwflmod, 0, addr);
+         printf ("%*s[%4" PRIuMAX "] %s %s\n",
+                 indent, "", (uintmax_t) offset, known[op], a);
+         free (a);
+
+         offset += 1 + addrsize;
+         break;
+
+       case DW_OP_call_ref:
+         /* Offset operand.  */
+         NEED (offset_size);
+         if (offset_size == 4)
+           addr = read_4ubyte_unaligned (dbg, data);
+         else
            {
-             char *a = format_dwarf_addr (dwflmod, 0, addr);
-             printf ("%*s[%4" PRIuMAX "] %s %s\n",
-                     indent, "", (uintmax_t) offset, known[op], a);
-             free (a);
+             assert (offset_size == 8);
+             addr = read_8ubyte_unaligned (dbg, data);
            }
-         else
-           printf ("%*s[%4" PRIuMAX "] %s %#" PRIxMAX "\n",
-                   indent, "", (uintmax_t) offset,
-                   known[op], (uintmax_t) addr);
-         offset += 1 + addrsize;
+         data += offset_size;
+         len -= offset_size;
+
+         printf ("%*s[%4" PRIuMAX "] %s %#" PRIxMAX "\n",
+                 indent, "", (uintmax_t) offset,
+                 known[op], (uintmax_t) addr);
+         offset += 1 + offset_size;
          break;
 
        case DW_OP_deref_size:
@@ -4520,7 +4533,7 @@ print_cfa_program (const unsigned char *readp, const unsigned char *const endp,
            // XXX overflow check
            get_uleb128 (op1, readp);   /* Length of DW_FORM_block.  */
            printf ("     def_cfa_expression %" PRIu64 "\n", op1);
-           print_ops (dwflmod, dbg, 10, 10, ptr_size, op1, readp);
+           print_ops (dwflmod, dbg, 10, 10, ptr_size, 0, op1, readp);
            readp += op1;
            break;
          case DW_CFA_expression:
@@ -4529,7 +4542,7 @@ print_cfa_program (const unsigned char *readp, const unsigned char *const endp,
            get_uleb128 (op2, readp);   /* Length of DW_FORM_block.  */
            printf ("     expression r%" PRIu64 " (%s) \n",
                    op1, regname (op1));
-           print_ops (dwflmod, dbg, 10, 10, ptr_size, op2, readp);
+           print_ops (dwflmod, dbg, 10, 10, ptr_size, 0, op2, readp);
            readp += op2;
            break;
          case DW_CFA_offset_extended_sf:
@@ -4572,7 +4585,7 @@ print_cfa_program (const unsigned char *readp, const unsigned char *const endp,
            get_uleb128 (op2, readp);   /* Length of DW_FORM_block.  */
            printf ("     val_expression r%" PRIu64 " (%s)\n",
                    op1, regname (op1));
-           print_ops (dwflmod, dbg, 10, 10, ptr_size, op2, readp);
+           print_ops (dwflmod, dbg, 10, 10, ptr_size, 0, op2, readp);
            readp += op2;
            break;
          case DW_CFA_MIPS_advance_loc8:
@@ -5098,6 +5111,7 @@ struct attrcb_args
   Dwarf *dbg;
   int level;
   unsigned int addrsize;
+  unsigned int offset_size;
   Dwarf_Off cu_offset;
 };
 
@@ -5301,7 +5315,8 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
        case DW_AT_upper_bound:
          print_ops (cbargs->dwflmod, cbargs->dbg,
                     12 + level * 2, 12 + level * 2,
-                    cbargs->addrsize, block.length, block.data);
+                    cbargs->addrsize, cbargs->offset_size,
+                    block.length, block.data);
          break;
 
        default:
@@ -5359,11 +5374,14 @@ print_debug_info_section (Dwfl_Module *dwflmod,
          (uint64_t) offset, /*version*/2, abbroffset, addrsize, offsize);
 
 
-  struct attrcb_args args;
-  args.dwflmod = dwflmod;
-  args.dbg = dbg;
-  args.addrsize = addrsize;
-  args.cu_offset = offset;
+  struct attrcb_args args =
+    {
+      .dwflmod = dwflmod,
+      .dbg = dbg,
+      .addrsize = addrsize,
+      .offset_size = offsize,
+      .cu_offset = offset
+    };
 
   offset += cuhl;
 
@@ -5900,6 +5918,10 @@ print_debug_loc_section (Dwfl_Module *dwflmod,
 
   size_t address_size = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
 
+  /* XXX This is wrong!  We can only know the right size given the CU that
+     points to this location list.  */
+  size_t offset_size = 4;
+
   bool first = true;
   unsigned char *readp = data->d_buf;
   while (readp < (unsigned char *) data->d_buf + data->d_size)
@@ -5952,7 +5974,7 @@ print_debug_loc_section (Dwfl_Module *dwflmod,
          free (e);
 
          print_ops (dwflmod, dbg, 1, 18 + (address_size * 4),
-                    address_size, len, readp);
+                    address_size, offset_size, len, readp);
 
          first = false;
          readp += len;