From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 10378 invoked by alias); 12 Mar 2008 13:26:32 -0000 Received: (qmail 10349 invoked by uid 9112); 12 Mar 2008 13:26:31 -0000 Date: Wed, 12 Mar 2008 13:26:00 -0000 Message-ID: <20080312132630.10334.qmail@sourceware.org> From: mark@sourceware.org To: frysk-cvs@sourceware.org Subject: [SCM] master: Implement libunwind fallback for plt frame. Fixes bug #5259 on x86. X-Git-Refname: refs/heads/master X-Git-Reftype: branch X-Git-Oldrev: 85a44d9747806bcf10bb63c835a9f7074cef8e7a X-Git-Newrev: cba040e1437a19ae0f0b21d560b13cb6d2091282 Mailing-List: contact frysk-cvs-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Post: List-Help: , Sender: frysk-cvs-owner@sourceware.org Reply-To: frysk@sourceware.org X-SW-Source: 2008-q1/txt/msg00346.txt.bz2 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 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 * 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 * 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 Date: Wed Mar 12 13:35:53 2008 +0100 Add toString to Frame. frysk-core/frysk/stack/ChangeLog 2008-03-12 Mark Wielaard * 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 + + * 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 + + * Frame.java (toString): New method. + 2008-03-10 Mark Wielaard * 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 toPrint() + * 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 + + * 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 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