Differences

This shows you the differences between two versions of the page.

Link to this comparison view

gdb_syscall_mips_patch [2011/09/20 20:43] (current)
Line 1: Line 1:
 +http://​sourceware.org/​ml/​gdb-patches/​2010-03/​msg00935.html\\
  
 +uClibc syscall() is macro which modifies stack before syscall
 +instruction,​ gdb is only looking at function prologue and misses the
 +stack modification made in syscall(). Because of this unwind doesn'​t
 +work. Attached is a patch, which is looking at actual $pc and $pc-4,
 +and in case of syscall it modifies $sp, so mip32_scan_prologue finds
 +correct values.
 +
 +Description of bug is also available here:
 +http://​www.listware.net/​201003/​gnu-gdb/​26893.html
 +
 +2010-03-27 ​ Jan Stancek ​ <​jan.stancek@gmail.com>​
 +        * mips-tdep.c:​ fix stack unwind through uClibc syscall() on mips
 +
 +--- cut ---
 +
 +<code c>
 +--- mips-tdep.c.orig ​   2010-03-27 17:​04:​57.000000000 +0100
 ++++ mips-tdep.c 2010-03-27 18:​47:​46.000000000 +0100
 +@@ -1895,6 +1895,44 @@ reset_saved_regs (struct gdbarch *gdbarc
 +   }
 + }
 +
 ++/*
 ++ * fix the $sp by looking around actual $pc
 ++ * Currently this handles only uClibc syscalls,
 ++ * which adjust $sp before syscall itsels
 ++ */
 ++int mips32_get_sp_adjustment(struct frame_info *this_frame,​ CORE_ADDR start_pc)
 ++{
 ++  CORE_ADDR pc = get_frame_address_in_block (this_frame);​
 ++  struct gdbarch *gdbarch = get_frame_arch (this_frame);​
 ++  unsigned long inst, high_word, low_word, ret;
 ++  int reg;
 ++
 ++  inst = (unsigned long) mips_fetch_instruction (gdbarch, pc);
 ++
 ++  ret = 0;
 ++  high_word = (inst >> 16) & 0xffff;
 ++  low_word = inst & 0xffff;
 ++  reg = high_word & 0x1f;
 ++
 ++  if (high_word == 0x27bd ​              /* addiu $sp,$sp,-i */
 ++      || high_word == 0x23bd ​           /* addi $sp,$sp,-i */
 ++      || high_word == 0x67bd) ​          /* daddiu $sp,$sp,-i */
 ++    {
 ++      if ( reg == MIPS_SP_REGNUM
 ++          && (low_word & 0x8000) == 0   /* positive stack adjustment */
 ++          && (pc-4) > start_pc )
 ++        {
 ++          pc = pc - 4;
 ++          inst = (unsigned long) mips_fetch_instruction (gdbarch, pc);
 ++          if (inst==0x0000000c) ​        /* syscall */
 ++            {
 ++              ret = low_word;
 ++            }
 ++        }
 ++    }
 ++  return ret;
 ++}
 ++
 + /* Analyze the function prologue from START_PC to LIMIT_PC. Builds
 +    the associated FRAME_CACHE if not null.
 +    Return the address of the first instruction past the prologue. ​ */
 +@@ -1920,9 +1958,12 @@ mips32_scan_prologue (struct gdbarch *gd
 +   /* Can be called when there'​s no process, and hence when there'​s no
 +      THIS_FRAME. ​ */
 +   if (this_frame != NULL)
 +-    sp = get_frame_register_signed (this_frame,​
 +-                                   ​gdbarch_num_regs (gdbarch)
 +-                                   + MIPS_SP_REGNUM);​
 ++    {
 ++      sp = get_frame_register_signed (this_frame,​
 ++              gdbarch_num_regs (gdbarch)
 ++              + MIPS_SP_REGNUM);​
 ++      sp += mips32_get_sp_adjustment(this_frame,​ start_pc);
 ++    }
 +   else
 +     sp = 0;
 +    ​
 +</​code> ​
Back to top
gdb_syscall_mips_patch.txt · Last modified: 2011/09/20 20:43 (external edit)
Sitemap Search: