From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 9536 invoked by alias); 19 Mar 2008 22:43:44 -0000 Received: (qmail 9507 invoked by uid 9112); 19 Mar 2008 22:43:43 -0000 Date: Wed, 19 Mar 2008 22:43:00 -0000 Message-ID: <20080319224343.9491.qmail@sourceware.org> From: mark@sourceware.org To: frysk-cvs@sourceware.org Subject: [SCM] master: Implement libunwind fallback for x86_64 plt frames. X-Git-Refname: refs/heads/master X-Git-Reftype: branch X-Git-Oldrev: 882074b248f05b4f67c402d4d8919cfb6cd8d581 X-Git-Newrev: d24ca531c9232260facb01c95eecab0263f4d391 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/msg00411.txt.bz2 The branch, master has been updated via d24ca531c9232260facb01c95eecab0263f4d391 (commit) from 882074b248f05b4f67c402d4d8919cfb6cd8d581 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email. - Log ----------------------------------------------------------------- commit d24ca531c9232260facb01c95eecab0263f4d391 Author: Mark Wielaard Date: Wed Mar 19 22:50:50 2008 +0100 Implement libunwind fallback for x86_64 plt frames. frysk-core/frysk/stack/ChangeLog 2008-03-19 Mark Wielaard * TestLibFunctionStepFrame.java: No longer unresolved on x86_64. frysk-imports/libunwind/ChangeLog 2007-03-19 Mark Wielaard * src/x86_64/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. ----------------------------------------------------------------------- Summary of changes: frysk-core/frysk/stack/ChangeLog | 4 + .../frysk/stack/TestLibFunctionStepFrame.java | 2 +- frysk-imports/libunwind/ChangeLog | 7 ++ frysk-imports/libunwind/src/x86_64/Gstep.c | 69 +++++++++++++++++++- 4 files changed, 80 insertions(+), 2 deletions(-) First 500 lines of diff: diff --git a/frysk-core/frysk/stack/ChangeLog b/frysk-core/frysk/stack/ChangeLog index 47a781f..1f1a2a9 100644 --- a/frysk-core/frysk/stack/ChangeLog +++ b/frysk-core/frysk/stack/ChangeLog @@ -1,3 +1,7 @@ +2008-03-19 Mark Wielaard + + * TestLibFunctionStepFrame.java: No longer unresolved on x86_64. + 2008-03-12 Mark Wielaard * TestLibFunctionStepFrame.java: Mark only unresolved on x86_64 diff --git a/frysk-core/frysk/stack/TestLibFunctionStepFrame.java b/frysk-core/frysk/stack/TestLibFunctionStepFrame.java index d71f5ac..2a746a0 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 (unresolvedOnx8664(5259) || unresolvedOnPPC(5259)) + if (unresolvedOnPPC(5259)) return; String source = Config.getRootSrcDir() diff --git a/frysk-imports/libunwind/ChangeLog b/frysk-imports/libunwind/ChangeLog index c34bbe9..9973254 100644 --- a/frysk-imports/libunwind/ChangeLog +++ b/frysk-imports/libunwind/ChangeLog @@ -1,3 +1,10 @@ +2007-03-19 Mark Wielaard + + * src/x86_64/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-03-12 Mark Wielaard * src/x86/Gstep.c (is_call_instr_at): New function. diff --git a/frysk-imports/libunwind/src/x86_64/Gstep.c b/frysk-imports/libunwind/src/x86_64/Gstep.c index fe69929..e5ed7b9 100644 --- a/frysk-imports/libunwind/src/x86_64/Gstep.c +++ b/frysk-imports/libunwind/src/x86_64/Gstep.c @@ -4,6 +4,9 @@ Modified for x86_64 by Max Asbock + Copyright (C) 2008 Red Hat, Inc. + Contributed by Mark Wielaard + This file is part of libunwind. Permission is hereby granted, free of charge, to any person obtaining @@ -83,6 +86,59 @@ code_descriptor_trap (struct cursor *c, struct dwarf_loc *rip_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); + Debug (99, "ret %d, instr 0x%x\n", ret, 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[RIP], &ip); + if (ret < 0) + return ret; + + ret = dwarf_get (&c->dwarf, c->dwarf.loc[RSP], &cfa); + if (ret < 0) + return ret; + + // See if one of the top 3 elements on the stack contains a + // return address. + int i; + for (i = 0; i <= 16; i += 8) + { + Debug (99, "trying %d\n", i); + ret = dwarf_get (&c->dwarf, DWARF_LOC (c->dwarf.cfa + i, 0), addr); + if (ret < 0) + return ret; + + Debug (99, "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) { @@ -91,6 +147,7 @@ unw_step (unw_cursor_t *cursor) struct dwarf_loc rip_loc; int rip_loc_set = 0; unw_word_t prev_ip = c->dwarf.ip, prev_cfa = c->dwarf.cfa; + unw_word_t addr; Debug (1, "(cursor=%p, ip=0x%016llx)\n", c, (unsigned long long) c->dwarf.ip); @@ -186,6 +243,16 @@ unw_step (unw_cursor_t *cursor) c->dwarf.loc[RBP] = rbp_loc; c->dwarf.loc[RSP] = rsp_loc; } + else if((ret = init_stack_based_ret(c, &addr)) >= 0) + { + Debug (99, "init_stack_based_ret() %d (0x%x)\n", ret, addr); + c->dwarf.cfa += ret + 8; + c->dwarf.loc[RSP] = DWARF_LOC (c->dwarf.cfa, 0); + c->dwarf.loc[RIP] = DWARF_LOC (addr, 0); + c->dwarf.ret_addr_column = RIP; + c->dwarf.ip = addr; + return 1; + } else { unw_word_t rbp; @@ -258,6 +325,6 @@ unw_step (unw_cursor_t *cursor) return -UNW_EBADFRAME; ret = (c->dwarf.ip == 0) ? 0 : 1; - Debug (2, "returning %d\n", ret); + Debug (2, "dwarf.ip = 0x%x, returning %d\n", c->dwarf.ip, ret); return ret; } hooks/post-receive -- frysk system monitor/debugger