public inbox for frysk-cvs@sourceware.org
help / color / mirror / Atom feed
* [SCM]  master: Implement libunwind fallback for plt frame. Fixes bug #5259 on x86.
@ 2008-03-12 13:26 mark
  0 siblings, 0 replies; only message in thread
From: mark @ 2008-03-12 13:26 UTC (permalink / raw)
  To: frysk-cvs

The branch, master has been updated
       via  cba040e1437a19ae0f0b21d560b13cb6d2091282 (commit)
       via  98ecf5e76797e40a49b0cdcb4c98145ec24059bf (commit)
      from  85a44d9747806bcf10bb63c835a9f7074cef8e7a (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email.

- Log -----------------------------------------------------------------
commit cba040e1437a19ae0f0b21d560b13cb6d2091282
Author: Mark Wielaard <mwielaard@redhat.com>
Date:   Wed Mar 12 14:22:49 2008 +0100

    Implement libunwind fallback for plt frame. Fixes bug #5259 on x86.
    
    frysk-core/frysk/stack/ChangeLog
    2008-03-12  Mark Wielaard  <mwielaard@redhat.com>
    
           * TestLibFunctionStepFrame.java: Mark only unresolved on x86_64
           and ppc. Only check first 24 steps (bug #5917). Tighter check for
           main and foo order.
    
    frysk-imports/libunwind/ChangeLog
    2007-03-12  Mark Wielaard  <mwielaard@redhat.com>
    
           * src/x86/Gstep.c (is_call_instr_at): New function.
           (init_stack_based_ret): New function.
           (unw_step): Try stack based unwind with call instr, before
           fallback to frame pointer.

commit 98ecf5e76797e40a49b0cdcb4c98145ec24059bf
Author: Mark Wielaard <mwielaard@redhat.com>
Date:   Wed Mar 12 13:35:53 2008 +0100

    Add toString to Frame.
    
    frysk-core/frysk/stack/ChangeLog
    2008-03-12  Mark Wielaard  <mwielaard@redhat.com>
    
           * Frame.java (toString): New method.

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

Summary of changes:
 frysk-core/frysk/stack/ChangeLog                   |   10 +++
 frysk-core/frysk/stack/Frame.java                  |   20 +++++-
 .../frysk/stack/TestLibFunctionStepFrame.java      |   28 +++++--
 frysk-imports/libunwind/ChangeLog                  |    7 ++
 frysk-imports/libunwind/src/x86/Gstep.c            |   77 ++++++++++++++++++++
 5 files changed, 132 insertions(+), 10 deletions(-)

First 500 lines of diff:
diff --git a/frysk-core/frysk/stack/ChangeLog b/frysk-core/frysk/stack/ChangeLog
index 8ff178e..47a781f 100644
--- a/frysk-core/frysk/stack/ChangeLog
+++ b/frysk-core/frysk/stack/ChangeLog
@@ -1,3 +1,13 @@
+2008-03-12  Mark Wielaard  <mwielaard@redhat.com>
+
+	* TestLibFunctionStepFrame.java: Mark only unresolved on x86_64
+	and ppc. Only check first 24 steps (bug #5917). Tighter check for
+	main and foo order.
+	
+2008-03-12  Mark Wielaard  <mwielaard@redhat.com>
+
+	* Frame.java (toString): New method.
+	
 2008-03-10  Mark Wielaard  <mwielaard@redhat.com>
 
 	* TestLibFunctionStepFrame.java: New test for bug #5259.
diff --git a/frysk-core/frysk/stack/Frame.java b/frysk-core/frysk/stack/Frame.java
index e676008..bee5511 100644
--- a/frysk-core/frysk/stack/Frame.java
+++ b/frysk-core/frysk/stack/Frame.java
@@ -1,6 +1,6 @@
 // This file is part of the program FRYSK.
 //
-// Copyright 2007, Red Hat Inc.
+// Copyright 2007, 2008, Red Hat Inc.
 //
 // FRYSK is free software; you can redistribute it and/or modify it
 // under the terms of the GNU General Public License as published by
@@ -41,6 +41,7 @@ package frysk.stack;
 
 import java.io.File;
 import java.io.PrintWriter;
+import java.io.StringWriter;
 
 import lib.dwfl.Dwfl;
 import lib.dwfl.DwflModule;
@@ -192,7 +193,22 @@ public abstract class Frame {
 	    return "Unknown";
 	}
     }
-  
+
+    /**
+     * Returns a plain string representation if this frame.
+     * This is similar to the result of calling <code>toPrint()</code>
+     * with both printParameters and fullPaths set to false.
+     */
+    public String toString() {
+         StringWriter sw = new StringWriter();
+         PrintWriter pw = new PrintWriter(sw);
+         pw.print(this.getClass().getName());
+         pw.print('[');
+         toPrint(pw, false, false);
+         pw.print(']');
+         pw.flush();
+         return sw.toString();
+    }
 
     /**
      * Extracts OFFSET:LENGTH bytes of REGISTER storing them from
diff --git a/frysk-core/frysk/stack/TestLibFunctionStepFrame.java b/frysk-core/frysk/stack/TestLibFunctionStepFrame.java
index f1f8c59..d71f5ac 100644
--- a/frysk-core/frysk/stack/TestLibFunctionStepFrame.java
+++ b/frysk-core/frysk/stack/TestLibFunctionStepFrame.java
@@ -67,7 +67,7 @@ public class TestLibFunctionStepFrame
 {
   public void testStepIntoLibFunctionCall()
   {
-    if (unresolved(5259))
+    if (unresolvedOnx8664(5259) || unresolvedOnPPC(5259))
       return;
 
     String source = Config.getRootSrcDir()
@@ -116,7 +116,7 @@ public class TestLibFunctionStepFrame
     // We are at the first plt intruction (for the first time).
     long firstPLTAddress = task.getPC();
     Frame frame = StackFactory.createFrame(task);
-    assertFooAndMainOuterFrames("At first PLT address", frame);
+    assertFooAndMainOuterFrames("First entry in PLT", frame);
 
     // Count your steps. And bail out when there are too many.
     int steps = 1;
@@ -125,12 +125,15 @@ public class TestLibFunctionStepFrame
     while (currentPC != addressLast && steps < 1000)
       {
 	task.requestUnblock(this);
-	assertRunUntilStop("Do step: " + steps);
+	assertRunUntilStop("Do step: "
+			   + (seenSecondCall ? "second" : "")
+			   + steps);
 
 	currentPC = task.getPC();
 	if (currentPC == address2)
 	  {
 	    seenSecondCall = true;
+	    steps = 1;
 	    // When we step we should be at the first PLTAddress again.
 	    // One step and we should be at the first PLT instruction.
 	    task.requestUnblock(this);
@@ -139,14 +142,18 @@ public class TestLibFunctionStepFrame
 	    assertEquals("Second time in PLT", currentPC, firstPLTAddress);
 
 	    frame = StackFactory.createFrame(task);
-	    assertFooAndMainOuterFrames("Second time in PLT", frame);
+	    assertFooAndMainOuterFrames("Second entry in PLT", frame);
 	  }
-	else if (currentPC != addressLast)
+	else if (currentPC != addressLast && steps < 24)
 	  {
+	    // Only check first 24
 	    frame = StackFactory.createFrame(task);
-	    assertFooAndMainOuterFrames("Stepping, #" + steps
+	    assertFooAndMainOuterFrames("Stepping "
+					+ (seenSecondCall ? "second" : "")
+					+ ", #" + steps
 					+ " through (plt) call", frame);
 	  }
+	steps++;
       }
 
     assertTrue("less than a thousand steps", steps < 1000);
@@ -167,6 +174,7 @@ public class TestLibFunctionStepFrame
     assertTrue(message + " first inner frame should not be foo or main", ok);
 
     boolean foo_seen = false;
+    boolean main_seen = false;
     Frame outer = frame.getOuter();
     while (ok && outer != null)
       {
@@ -186,7 +194,11 @@ public class TestLibFunctionStepFrame
 
 	boolean sym_is_main = name.indexOf("main") != -1;
 	if (foo_seen && sym_is_main)
-	  break;
+	  {
+	    // Hurray done!
+	    main_seen = true;
+	    break;
+	  }
 
 	if (! foo_seen && sym_is_main)
 	  {
@@ -199,7 +211,7 @@ public class TestLibFunctionStepFrame
 	outer = outer.getOuter();
       }
 
-    ok = outer != null;
+    ok = ok && foo_seen && main_seen && outer != null;
     if (! ok)
       printBacktrace(frame);
     assertTrue(message
diff --git a/frysk-imports/libunwind/ChangeLog b/frysk-imports/libunwind/ChangeLog
index 6ecc99c..c34bbe9 100644
--- a/frysk-imports/libunwind/ChangeLog
+++ b/frysk-imports/libunwind/ChangeLog
@@ -1,3 +1,10 @@
+2007-03-12  Mark Wielaard  <mwielaard@redhat.com>
+
+	* src/x86/Gstep.c (is_call_instr_at): New function.
+	(init_stack_based_ret): New function.
+	(unw_step): Try stack based unwind with call instr, before
+	fallback to frame pointer.
+
 2007-01-31  Mark Wielaard  <mwielaard@redhat.com>
 
 	Fixup libunwind merge.
diff --git a/frysk-imports/libunwind/src/x86/Gstep.c b/frysk-imports/libunwind/src/x86/Gstep.c
index 618b8af..c9083cb 100644
--- a/frysk-imports/libunwind/src/x86/Gstep.c
+++ b/frysk-imports/libunwind/src/x86/Gstep.c
@@ -85,6 +85,72 @@ code_descriptor_trap (struct cursor *c, struct dwarf_loc *eip_loc_pointer)
   return 1;
 }
 
+// A CALL instruction starts with 0xFF.
+static int
+is_call_instr_at (struct cursor *c, unw_word_t addr)
+{
+  int ret;
+  unw_word_t instr;
+  ret = dwarf_get (&c->dwarf, DWARF_LOC (addr, 0), &instr);
+  return ret >= 0 && ((instr & 0xff000000) == 0xff000000);
+}
+
+// Checks whether this looks like a plt entry like cursor and returns
+// the stack offset where the return address can be found, or -1 if
+// not detected (also tries to make sure this is the inner most frame).
+// When this function returns positively (zero included) addr will
+// contain the return address.
+static int
+init_stack_based_ret (struct cursor *c, unw_word_t *addr)
+{
+  // See if this looks "clean", everything in actual registers
+  // which indicates this is most likely an inner most frame just
+  // initted.
+  int ret;
+  unw_word_t ip, cfa;
+  ret = dwarf_get (&c->dwarf, c->dwarf.loc[EIP], &ip);
+  if (ret < 0)
+    return ret;
+
+  ret = dwarf_get (&c->dwarf, c->dwarf.loc[ESP], &cfa);
+  if (ret < 0)
+    return ret;
+  
+  if (c->sigcontext_format == X86_SCF_NONE
+      && DWARF_IS_REG_LOC(c->dwarf.loc[EAX])
+      && DWARF_IS_REG_LOC(c->dwarf.loc[ECX])
+      && DWARF_IS_REG_LOC(c->dwarf.loc[EDX])
+      && DWARF_IS_REG_LOC(c->dwarf.loc[EBX])
+      && DWARF_IS_REG_LOC(c->dwarf.loc[ESP])
+      && DWARF_IS_REG_LOC(c->dwarf.loc[EBP])
+      && DWARF_IS_REG_LOC(c->dwarf.loc[ESI])
+      && DWARF_IS_REG_LOC(c->dwarf.loc[EDI])
+      && DWARF_IS_REG_LOC(c->dwarf.loc[EIP])
+      && DWARF_IS_REG_LOC(c->dwarf.loc[EFLAGS])
+      && DWARF_IS_REG_LOC(c->dwarf.loc[TRAPNO])
+      && ip == c->dwarf.ip && cfa == c->dwarf.cfa)
+    {
+      // See if one of the top 3 elements on the stack contains a
+      // return address.
+      int i;
+      for (i = 0; i <= 8; i += 4)
+	{
+	  // fprintf(stderr, "trying %d\n", i);
+	  ret = dwarf_get (&c->dwarf, DWARF_LOC (c->dwarf.cfa + i, 0), addr);
+	  if (ret < 0)
+	    return ret;
+
+	  // fprintf(stderr, "addr at %d: 0x%x\n", i, *addr);
+	  // Sanity check the address, not too low, and must
+	  // come from a call instruction.
+	  if (*addr > 0 && is_call_instr_at(c, (*addr) - 5))
+	    return i;
+	}
+    }
+
+  return -1;
+}
+
 PROTECTED int
 unw_step (unw_cursor_t *cursor)
 {
@@ -92,6 +158,7 @@ unw_step (unw_cursor_t *cursor)
   int ret, i;
   struct dwarf_loc eip_loc;
   int eip_loc_set = 0;
+  unw_word_t addr;
 
   Debug (1, "(cursor=%p, ip=0x%08x)\n", c, (unsigned) c->dwarf.ip);
 
@@ -202,6 +269,16 @@ unw_step (unw_cursor_t *cursor)
 	  c->dwarf.loc[TRAPNO] = DWARF_NULL_LOC;
 	  c->dwarf.loc[ST0] = DWARF_NULL_LOC;
 	}
+      else if((ret = init_stack_based_ret(c, &addr)) >= 0)
+	{
+	  // fprintf(stderr, "init_stack_based_ret() %d (0x%x)\n", ret, addr);
+	  c->dwarf.cfa += ret;
+	  c->dwarf.loc[ESP] = DWARF_LOC (c->dwarf.cfa, 0);
+	  c->dwarf.loc[EIP] = DWARF_LOC (addr, 0);
+	  c->dwarf.ret_addr_column = EIP;
+	  c->dwarf.ip = addr;
+	  return 1;
+	}
       else
 	{
 	  ret = dwarf_get (&c->dwarf, c->dwarf.loc[EBP], &c->dwarf.cfa);


hooks/post-receive
--
frysk system monitor/debugger


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2008-03-12 13:26 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-03-12 13:26 [SCM] master: Implement libunwind fallback for plt frame. Fixes bug #5259 on x86 mark

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).