This is the mail archive of the gdb@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Debugging a frameless function


I'm trying to debug a problem in the DJGPP build of a recent GDB
snapshot, whereby stepping into a function compiled with
"-fomit-frame-pointer" throws an error:

   Cannot access memory at address 0x12

I reproduce below the test program and the transcript of a GDB session
where I try to debug this.  Any hints or ideas are welcome.  TIA

>From what I see, a call to read_reg in dwarf2_frame_cache, that tries
to read the value of EBP, ends up calling
sentinel_frame_prev_register, and from there eventually
target_fetch_registers is called.  But since we are in a frameless
function, EBP holds a variable, not the frame pointer, so the value
fetched by target_fetch_registers is 2, which later causes
dwarf2_frame_this_id to call frame_id_build with the first argument
whose value is 0x16, so the address of the stack in that frame is
bogus.  And that is what causes the above error message.

When I run the same program on GNU/Linux, the problem does not
happen.  But the GNU/Linux box to which I have access is a 64-bit
machine, so the architecture-dependent bits there are different, and I
cannot easily compare what the code does on these two systems.

My question is, how should GDB overcome the difficulty of a frameless
function, when it tries to unwind a frame where EBP is used for
holding a variable?  Can someone please spot any missing pieces in the
session below, and give me hints on where to look for the source of
the trouble?

I see other failures in the DJGPP port that somehow seem related to
dwarf2-frame.c functions, so I believe solving this problem will let
me solve others as well.  The problem doesn't happen in the same
program compiled with -gstabs+ rather than using DWARF2 debug info.

Here's the program I used.  Compile it with -g -O -fomit-frame-pointer
to get the argument `n' of the function `foo' stored in EBP.

---------------------------------
#include <stdio.h>
#include <stdlib.h>

int
foo (register int n)
{
  register int i;
  register int a = n * 1;
  register int b = n * 2;
  register int c = n * 3;
  register int d = n * 4;
  register int e = n * 5;

  for (i = 0; i < n; i++)
    {
      if (i & 1)  a = b + c; else a = c + e;
      if (i & 2)  b = c + d; else b = d + a;
      if (i & 4)  c = d + e; else c = e + b;
      if (i & 8)  d = e + a; else d = a + c;
      if (i & 16) e = a + b; else e = b + d;
    }

  return a + b + c + d + e;
}


int
main (int argc, char **argv)
{
  if (argc == 2)
    printf ("%d\n", foo (atoi (argv[1])));
}

---------------------------

And here is the debugging session mentioned above.  I use GDB 6.1 to
debug the April 10th snapshot:

D:\usr\djgpp\gnu\gdb-68.410\gdb>d:\usr\djgpp\bin\gdb ./gdb.exe
GNU gdb 6.1
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "--host=i386-pc-msdosdjgpp --target=djgpp"...
Setting up the environment for debugging gdb.
During symbol reading, debug info gives macro definition outside of any file: __STDC_HOSTED__ 1.
During symbol reading, no terminating 0-type entry for macros in `.debug_macinfo' section.
Breakpoint 1 at 0x660f: file utils.c, line 993.
Breakpoint 2 at 0xaae1: file .././gdb/cli/cli-cmds.c, line 199.
(top-gdb) break dwarf2_frame_cache
Breakpoint 3 at 0x11f9f2: file dwarf2-frame.c, line 874.
(top-gdb) r --nx ./frame_d.exe
Starting program: d:/usr/djgpp/gnu/gdb-68.410/gdb/./gdb.exe --nx ./frame_d.exe
GNU gdb (GDB) 6.8.50.20090410
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=i586-pc-msdosdjgpp --target=djgpp".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
(gdb) break foo
Breakpoint 1 at 0x1680: file frameless.c, line 6.
(gdb) r 2
Starting program: d:/usr/djgpp/gnu/gdb-68.410/gdb/./frame_d.exe 2


Breakpoint 3, dwarf2_frame_cache (this_frame=0x418dec, this_cache=0x418df0)
    at dwarf2-frame.c:874
874          struct gdbarch *gdbarch = get_frame_arch (this_frame);
(top-gdb) c
Continuing.
Breakpoint 1, foo (n=588648) at frameless.c:6
6        {
(gdb) n

Breakpoint 3, dwarf2_frame_cache (this_frame=0x418dec, this_cache=0x418df0)
    at dwarf2-frame.c:874
874          struct gdbarch *gdbarch = get_frame_arch (this_frame);
(top-gdb) n
875          const int num_regs = gdbarch_num_regs (gdbarch)
(top-gdb) until 932
932          execute_cfa_program (fde, fde->instructions, fde->end, this_frame,
fs);
(top-gdb) n
935          switch (fs->cfa_how)
(top-gdb)
938              cache->cfa = read_reg (this_frame, fs->cfa_reg);
(top-gdb) s
read_reg (baton=0x418dec, reg=5) at dwarf2-frame.c:277
277          struct gdbarch *gdbarch = get_frame_arch (this_frame);
(top-gdb) n
281          regnum = gdbarch_dwarf2_reg_to_regnum (gdbarch, reg);
(top-gdb) n
283          buf = alloca (register_size (gdbarch, regnum));
(top-gdb) p regnum
$10 = 5
(top-gdb) n
284          get_frame_register (this_frame, regnum, buf);
(top-gdb) s
get_frame_register (frame=0x20, regnum=5, buf=0x3e84d0 "\005") at frame.c:653
653          frame_unwind_register (frame->next, regnum, buf);
(top-gdb) s
frame_unwind_register (frame=0x418da0, regnum=5, buf=0x3e84d0 "\005")
    at frame.c:645
645          frame_register_unwind (frame, regnum, &optimized, &lval, &addr,
(top-gdb) s
frame_register_unwind (frame=0x418da0, regnum=5, optimizedp=0x3e8488,
    lvalp=0x3e848c, addrp=0x3e8490, realnump=0x3e8494, bufferp=0x3e84d0 "\005")
    at frame.c:593
593          gdb_assert (optimizedp != NULL);
(top-gdb) n
594          gdb_assert (lvalp != NULL);
(top-gdb)
595          gdb_assert (addrp != NULL);
(top-gdb)
596          gdb_assert (realnump != NULL);
(top-gdb)
599          value = frame_unwind_register_value (frame, regnum);
(top-gdb) s
frame_unwind_register_value (frame=0x418da0, regnum=5) at frame.c:661
661          gdb_assert (frame != NULL);
(top-gdb) n
663          if (frame_debug)
(top-gdb)
673          if (frame->unwind == NULL)
(top-gdb)
677          value = frame->unwind->prev_register (frame, &frame->prologue_cache
, regnum);
(top-gdb) s
sentinel_frame_prev_register (this_frame=0x418da0,
    this_prologue_cache=0xbc9a4, regnum=5) at sentinel-frame.c:50
50          struct gdbarch *gdbarch = get_frame_arch (this_frame);
(top-gdb) n
51          struct frame_unwind_cache *cache = *this_prologue_cache;
(top-gdb)
55          value = allocate_value (register_type (gdbarch, regnum));
(top-gdb)
56          VALUE_LVAL (value) = lval_register;
(top-gdb)
57          VALUE_REGNUM (value) = regnum;
(top-gdb)
58          VALUE_FRAME_ID (value) = get_frame_id (this_frame);
(top-gdb)
63          regcache_cooked_read (cache->regcache, regnum, value_contents_raw (v
alue));
(top-gdb) s
value_contents_raw (value=0x439ed0) at value.c:399
399          allocate_value_contents (value);
(top-gdb) n
400          return value->contents + value->embedded_offset;
(top-gdb) p value
$12 = (struct value *) 0x439ed0
(top-gdb) p *value
$13 = {lval = lval_register, modifiable = 1, location = {address = 0,
    internalvar = 0x0, computed = {funcs = 0x0, closure = 0x0}}, offset = 0,
  bitsize = 0, bitpos = 0, frame_id = {stack_addr = 0, code_addr = 0,
    special_addr = 0, stack_addr_p = 0, code_addr_p = 0, special_addr_p = 0},
  type = 0x44ee48, enclosing_type = 0x44ee48, embedded_offset = 0,
  pointed_to_offset = 0, next = 0x0, regnum = 5, lazy = 0 '\0',
  optimized_out = 0 '\0', initialized = 1, contents = 0x439f28 ""}
(top-gdb) n
401        }
(top-gdb) s
regcache_cooked_read (regcache=0x44f4d8, regnum=5, buf=0x439f28 "")
    at regcache.c:581
581          gdb_assert (regnum >= 0);
(top-gdb) n
582          gdb_assert (regnum < regcache->descr->nr_cooked_registers);
(top-gdb) p regcache->descr
$14 = (struct regcache_descr *) 0x435dcc
(top-gdb) p *regcache->descr
$15 = {gdbarch = 0x435b00, nr_raw_registers = 32, sizeof_raw_registers = 240,
  sizeof_raw_register_valid_p = 40, nr_cooked_registers = 40,
  sizeof_cooked_registers = 240, sizeof_cooked_register_valid_p = 40,
  register_offset = 0x435fa8, sizeof_register = 0x435f08,
  register_type = 0x435df4}
(top-gdb) n
583          if (regnum < regcache->descr->nr_raw_registers)
(top-gdb)
584            regcache_raw_read (regcache, regnum, buf);
(top-gdb) s
regcache_raw_read (regcache=0x44f4d8, regnum=5, buf=0x439f28 "")
    at regcache.c:500
500          gdb_assert (regcache != NULL && buf != NULL);
(top-gdb) n
501          gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_raw_registe
rs);
(top-gdb)
506          if (!regcache->readonly_p)
(top-gdb)
508              if (!regcache_valid_p (regcache, regnum))
(top-gdb)
510                  struct cleanup *old_chain = save_inferior_ptid ();
(top-gdb)
511                  inferior_ptid = regcache->ptid;
(top-gdb)
512                  target_fetch_registers (regcache, regnum);
(top-gdb) p regnum
$17 = 5
(top-gdb) s
target_fetch_registers (regcache=0x44f4d8, regno=5) at target.c:2744
2744          for (t = current_target.beneath; t != NULL; t = t->beneath)
(top-gdb) s
2746              if (t->to_fetch_registers != NULL)
(top-gdb)
2748                  t->to_fetch_registers (t, regcache, regno);
(top-gdb)
go32_fetch_registers (ops=0x347828, regcache=0x44f4d8, regno=5)
    at go32-nat.c:490
490          if (regno >= 0)
(top-gdb) n
491            fetch_register (regcache, regno);
(top-gdb)
500        }
(top-gdb)
target_fetch_registers (regcache=0x44f4d8, regno=5) at target.c:2749
2749                  if (targetdebug)
(top-gdb)
2754        }
(top-gdb)
regcache_raw_read (regcache=0x44f4d8, regnum=5, buf=0x439f28 "")
    at regcache.c:513
513                  do_cleanups (old_chain);
(top-gdb)
526          memcpy (buf, register_buffer (regcache, regnum),
(top-gdb)
528        }
(top-gdb)
regcache_cooked_read (regcache=0x5, regnum=5, buf=0x439f28 "\002")
    at regcache.c:594
594        }
(top-gdb)
sentinel_frame_prev_register (this_frame=0x418da0, this_prologue_cache=0x5,
    regnum=5) at sentinel-frame.c:66
66        }
(top-gdb)
frame_unwind_register_value (frame=0x418da0, regnum=5) at frame.c:679
679          if (frame_debug)
(top-gdb)
714        }
(top-gdb)
frame_register_unwind (frame=0x418da0, regnum=5, optimizedp=0x3e8488,
    lvalp=0x3e848c, addrp=0x3e8490, realnump=0x3e8494, bufferp=0x3e84d0 "\005")
    at frame.c:601
601          gdb_assert (value != NULL);
(top-gdb)
603          *optimizedp = value_optimized_out (value);
(top-gdb)
604          *lvalp = VALUE_LVAL (value);
(top-gdb)
605          *addrp = VALUE_ADDRESS (value);
(top-gdb)
606          *realnump = VALUE_REGNUM (value);
(top-gdb)
608          if (bufferp)
(top-gdb)
609            memcpy (bufferp, value_contents_all (value),
(top-gdb)
614          release_value (value);
(top-gdb)
615          value_free (value);
(top-gdb)
616        }
(top-gdb)
frame_unwind_register (frame=0x418da0, regnum=5, buf=0x3e84d0 "\002")
    at frame.c:647
647        }
(top-gdb)
get_frame_register (frame=0x0, regnum=5, buf=0x3e84d0 "\002") at frame.c:654
654        }
(top-gdb)
read_reg (baton=0x418dec, reg=5) at dwarf2-frame.c:291
291          return unpack_long (register_type (gdbarch, regnum), buf);
(top-gdb)
292        }
(top-gdb)
dwarf2_frame_cache (this_frame=0x418dec, this_cache=0x418df0)
    at dwarf2-frame.c:939
939              if (fs->armcc_cfa_offsets_reversed)
(top-gdb) l
934          /* Calculate the CFA.  */
935          switch (fs->cfa_how)
936            {
937            case CFA_REG_OFFSET:
938              cache->cfa = read_reg (this_frame, fs->cfa_reg);
939              if (fs->armcc_cfa_offsets_reversed)
940                cache->cfa -= fs->cfa_offset;
941              else
942                cache->cfa += fs->cfa_offset;
943              break;
(top-gdb) p cache->cfa
$18 = 2
(top-gdb) c
Continuing.

Breakpoint 3, dwarf2_frame_cache (this_frame=0x418dec, this_cache=0x418df0)
    at dwarf2-frame.c:874
874          struct gdbarch *gdbarch = get_frame_arch (this_frame);
(top-gdb) c
Continuing.
Cannot access memory at address 0x12


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]