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);