From patchwork Tue Mar 11 01:46:47 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Smundak X-Patchwork-Id: 28 Return-Path: X-Original-To: siddhesh@wilcox.dreamhost.com Delivered-To: siddhesh@wilcox.dreamhost.com Received: from homiemail-mx22.g.dreamhost.com (caibbdcaabij.dreamhost.com [208.113.200.189]) by wilcox.dreamhost.com (Postfix) with ESMTP id 526EB3600F0 for ; Mon, 10 Mar 2014 18:46:56 -0700 (PDT) Received: by homiemail-mx22.g.dreamhost.com (Postfix, from userid 14314964) id E5B1D4B86038; Mon, 10 Mar 2014 18:46:55 -0700 (PDT) X-Original-To: gdb@patchwork.siddhesh.in Delivered-To: x14314964@homiemail-mx22.g.dreamhost.com Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by homiemail-mx22.g.dreamhost.com (Postfix) with ESMTPS id 931914B5BA6D for ; Mon, 10 Mar 2014 18:46:55 -0700 (PDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:mime-version:in-reply-to:references:date :message-id:subject:from:to:cc:content-type; q=dns; s=default; b= YSvBtk7ZsxjLNLHROq14eeRXBHNSsbgemOwWB3ZW2qTxBp/j+B8JLnXngWtbR+U6 MQSav7GyW1/WWJ9gf5eUZDR4cUAzgSIMPZGsxV/oICnjpqzR+RNi1fwIKYCRLE7l M8EDz703yWpiJ4hGoh1V/OqlrbXJmJP4uoikZJ1E0/8= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:mime-version:in-reply-to:references:date :message-id:subject:from:to:cc:content-type; s=default; bh=qFcR4 9n8N/cQfJwwRjGLAg8GrO8=; b=okzRfpwZgQBFAlH0XTwCSHqozyU5oRd8k/NTE ZR8L55ZGtF2WNkMlemxAXVcV9ikpWgr9cKUiGXkGJ7MXpalLt2VSZHEytzCqLFbJ yqSXVsJEBrgdBDYaH9ite+eL2V+7Gdzum6ZKeXfOqUT6jJunl7QOqN9qr6e2eNA4 MB6eqY= Received: (qmail 31903 invoked by alias); 11 Mar 2014 01:46:52 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 31890 invoked by uid 89); 11 Mar 2014 01:46:51 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.1 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_LOW, SPF_PASS, T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-HELO: mail-oa0-f49.google.com Received: from mail-oa0-f49.google.com (HELO mail-oa0-f49.google.com) (209.85.219.49) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Tue, 11 Mar 2014 01:46:49 +0000 Received: by mail-oa0-f49.google.com with SMTP id g12so7701818oah.8 for ; Mon, 10 Mar 2014 18:46:47 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:in-reply-to:references:date :message-id:subject:from:to:cc:content-type; bh=+lc8PmztNuN/5TezZQVrYjCtqIA3WNqzOMj/fNg/uhw=; b=mmkoRt/6+07TqfTjCRh6Qx+QJgesXwxyQYkumwpLTOo/mRIirAijel0h+kLNSl1LEj QSz5jX81XOS3W2uPQ3A2KUFZrpYztFrH/mhABrUWBkBBshH2mfCPp/dkxwcfmVKmg1Dj DtNX5MZOxO/M6CtmBtZh62eFujPFPcpMw9ezNLiIFDWIaIA7h92SiWUXDhkCt0p3pfjm q6iTnDTqCRssIiZEkj7+5jkDL4JLuvjObeLgBtBq3Qx8IS4YyR8GEwZ5b/DO1I9Hqy2i mdLQyGAx2MhhafzRsmvjQLxPpUC6jocKFyZqiPJY0l+izwnUd/+YZF5JWGt7Ypd0mZBF L7Qg== X-Gm-Message-State: ALoCoQmk9tT4/CDtrBQzmVs6e5G3DZKG40YDKwtjzKeZ3btMYJSfft8a1w85cUVk45SISGvO4O7yNw40lFPVOimJt1I+IYfVSPB693uKAt69+zcT3IsNm9IOMSASwfTTqFjvGBj0/5Grz5L9R6kNVzuj5FgZ0AR5eB/c430ShwNtbl4WorNAXj8TV4tjvRNZsE6xuwgQZnEr05UmbNAsKeF8nwvLktjtVw== MIME-Version: 1.0 X-Received: by 10.60.134.137 with SMTP id pk9mr21621015oeb.40.1394502407594; Mon, 10 Mar 2014 18:46:47 -0700 (PDT) Received: by 10.182.84.131 with HTTP; Mon, 10 Mar 2014 18:46:47 -0700 (PDT) In-Reply-To: References: <20131226183618.D264CA18A0@sasha2.mtv.corp.google.com> <21204.13416.607204.485255@ruffy.mtv.corp.google.com> Date: Mon, 10 Mar 2014 18:46:47 -0700 Message-ID: Subject: Re: [RFC][PATCH] Allow JIT unwinder provide symbol information From: Alexander Smundak To: Doug Evans Cc: gdb-patches , Pedro Alves X-DH-Original-To: gdb@patchwork.siddhesh.in I apologize for the delay. On Mon, Feb 24, 2014 at 5:19 PM, Doug Evans wrote: > Thus I think(!) the only remaining issues are: > - jit-reader-load version 1 support. > - update documentation > - testcase for new functionality > - testcase to verify version 1 API still works > We can't break jit readers that have been compiled with the version 1 API. I started with writing the testcase for this (attached below). The test checks that a JIT reader can help GDB unwind the stack that could not be unwound otherwise. That is, the test application contains a function that deliberately corrupts the address of the outer frame when called (and then restores it). The test sets the breakpoint at the location where the backtrace is broken and verifies that the backtrace is shown correctly only in the presence of a JIT reader (which happens to know where the correct outer frame was saved). This test fails with upstream GDB because JIT reader's unwinder is never called. Which IMHO is an indication that JIT reader in its current form is unlikely to be used. And the absence of any tests that involve loading JIT reader points in the same direction. Sasha diff --git a/gdb/testsuite/gdb.arch/amd64-jit-reader.c b/gdb/testsuite/gdb.arch/amd64-jit-reader.c new file mode 100644 index 0000000..2887abd --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-jit-reader.c @@ -0,0 +1,117 @@ +#include +#include +#include "jit-reader.h" + +GDB_DECLARE_GPL_COMPATIBLE_READER + +extern struct gdb_reader_funcs *gdb_init_reader (void); + +static enum gdb_status debug_info_provider (struct gdb_reader_funcs *self, + struct gdb_symbol_callbacks *cb, + void *memory, long memory_sz); +static enum gdb_status frame_unwinder (struct gdb_reader_funcs *self, + struct gdb_unwind_callbacks *cb); +static struct gdb_frame_id frame_id_provider(struct gdb_reader_funcs *self, + struct gdb_unwind_callbacks *cb); +static void destructor (struct gdb_reader_funcs *self); + +#define DATA_COOKIE 0xdeaffead +static int jit_data = DATA_COOKIE; + +static struct gdb_reader_funcs jit_reader_funcs = +{ + 1, /* version */ + (void *)&jit_data, + debug_info_provider, + frame_unwinder, + frame_id_provider, + destructor +}; + +struct gdb_reader_funcs * +gdb_init_reader (void) +{ + fprintf (stderr, "Test JIT reader loaded.\n"); + return &jit_reader_funcs; +} + +enum gdb_status +debug_info_provider (struct gdb_reader_funcs *self, + struct gdb_symbol_callbacks *cb, + void *memory, long memory_sz) +{ + if (*(int *)(self->priv_data) != DATA_COOKIE) + return GDB_FAIL; + fprintf (stderr, "Debug info provider called for %p..%p.\n", + memory, (void *)(memory_sz + (char *)memory)); + return GDB_SUCCESS; +} + +void +destructor (struct gdb_reader_funcs *self) +{ + fprintf (stderr, "Test JIT reader unloaded.\n"); + return; +} + +static GDB_CORE_ADDR +_get_frame_register (struct gdb_unwind_callbacks *cb, int reg_no) +{ + struct gdb_reg_value *reg = cb->reg_get (cb, reg_no); + GDB_CORE_ADDR reg_value = *(GDB_CORE_ADDR *)reg->value; + reg->free (reg); + return reg_value; +} + +static void +_set_frame_register (struct gdb_unwind_callbacks *cb, int reg_no, + GDB_CORE_ADDR value) +{ + struct gdb_reg_value *reg = cb->reg_get (cb, reg_no); + *(GDB_CORE_ADDR *)(reg->value) = value; + reg->defined = 1; + (cb->reg_set)(cb, reg_no, reg); +} + +#define REG_BP 6 +#define REG_PC 16 +#define REG_SP 7 +enum gdb_status +frame_unwinder (struct gdb_reader_funcs *self, + struct gdb_unwind_callbacks *cb) +{ + GDB_CORE_ADDR bp = _get_frame_register (cb, REG_BP); + GDB_CORE_ADDR pc = _get_frame_register (cb, REG_PC); + GDB_CORE_ADDR sp = _get_frame_register (cb, REG_SP); + GDB_CORE_ADDR word; + cb->target_read(bp, &word, 8); + if (word != bp) + return GDB_FAIL; + + /* We are at the frame that xxx-jit-unwind program altered for us. + We have: + BP-8 +--------------+ + | Previous BP | + BP +--------------+ + | BP (wrong!) | + BP+8 +--------------+ + | Previous PC | + +--------------+ + Save outer frame's BP, PC and SP. */ + cb->target_read (bp - 8, &word, 8); + _set_frame_register (cb, REG_BP, word); + cb->target_read (bp + 8, &word, 8); + _set_frame_register (cb, REG_PC, word); + _set_frame_register (cb, REG_SP, bp + 16); + return GDB_SUCCESS; +} + +struct gdb_frame_id frame_id_provider (struct gdb_reader_funcs *self, + struct gdb_unwind_callbacks *cb) +{ + struct gdb_frame_id frame_id = + { _get_frame_register (cb, REG_PC), + _get_frame_register (cb, REG_SP) }; + fprintf (stderr, "frame_id_provider called.\n"); + return frame_id; +} diff --git a/gdb/testsuite/gdb.arch/amd64-jit-reader.exp b/gdb/testsuite/gdb.arch/amd64-jit-reader.exp new file mode 100644 index 0000000..513e8b0 --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-jit-reader.exp @@ -0,0 +1,60 @@ +if {[skip_shlib_tests]} { + untested "Shared libraries are not supported" + return -1 +} + +if {[get_compiler_info]} { + return -1 +} + +if { ![istarget x86_64-*-* ] || ![is_lp64_target] } { + verbose "Skipping amd64 JIT reader tests." + return +} + +set testfile "amd64-jit-unwind" +set srcfile ${testfile}.c +set binfile [standard_output_file ${testfile}] +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug]] != "" } { + untested "could not compile test program" + return -1 +} + +set jit_reader "amd64-jit-reader" +set jit_reader_source "${srcdir}/${subdir}/${jit_reader}.c" +set jit_reader_binfile [standard_output_file ${jit_reader}.so] + +if { [gdb_compile_shlib ${jit_reader_source} ${jit_reader_binfile} {additional_flags="-I.."}] != "" } { + untested "Cannot compile amd-jit-reader" + return -1 +} + +# Check that GDB is unable to show the backtrace for jit-unwind without +# JIT reader. +clean_restart $testfile +if { ![runto_main] } { + fail "Can't run to main" + return +} +gdb_breakpoint [gdb_get_line_number "break backtrace-broken" ] +gdb_continue_to_breakpoint "break backtrace-broken" +gdb_test "where" "Backtrace stopped: frame did not save the .*" +gdb_test "continue" "Continuing\..*$inferior_exited_re.*" + +# Check that GDB shows backtrace with JIT reader present +# and that JIT reader can be unloaded. +clean_restart $testfile +if { ![runto_main] } { + fail "Can't run to main" + return +} +gdb_test "jit-reader-load ${jit_reader_binfile}" "Test JIT reader loaded." +gdb_breakpoint [gdb_get_line_number "break backtrace-broken" ] +gdb_continue_to_breakpoint "break backtrace-broken" +gdb_test_sequence "where" "Bad backtrace" { + "\[\r\n\]+#0 .* break_unwind_chain \\(\\) at " + "\[\r\n\]+#1 .* break_unwind_chain_1 \\(\\) at " + "\[\r\n\]+#2 .* main \\(.*\\) at" +} +gdb_test "continue" "Continuing\..*$inferior_exited_re.*" +gdb_test "jit-reader-unload" "Test JIT reader unloaded." diff --git a/gdb/testsuite/gdb.arch/amd64-jit-unwind.c b/gdb/testsuite/gdb.arch/amd64-jit-unwind.c new file mode 100644 index 0000000..c2ae3de --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-jit-unwind.c @@ -0,0 +1,43 @@ +/* This test program is part of GDB, the GNU debugger. + + Copyright 2011-2014 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* This program is used to verify that a JIT handler can unwind custom + stack frames. */ + +#include +#include +static void break_unwind_chain() +{ + /* Save outer frame address, then corrupt the frame chain by setting + the outer frame address in it to self. */ + void *outer_fp = *(void **)__builtin_frame_address(0); + *(void **)__builtin_frame_address(0) = __builtin_frame_address(0); + /* Now restore it so that we can return. The test sets the + breakpoint just before this happens, and GDB will not be able to + show the backtrace without JIT reader. */ + *(void **)__builtin_frame_address(0) = outer_fp; /* break backtrace-broken */ +} + +static void break_unwind_chain_1() +{ + break_unwind_chain(); +} + +int main(int argc, char *argv[]) +{ + break_unwind_chain_1(); +}