From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 25788 invoked by alias); 9 Aug 2011 15:21:44 -0000 Received: (qmail 25778 invoked by uid 22791); 9 Aug 2011 15:21:42 -0000 X-SWARE-Spam-Status: No, hits=-1.8 required=5.0 tests=AWL,BAYES_00,RCVD_IN_DNSWL_LOW,SPF_SOFTFAIL,TW_DB X-Spam-Check-By: sourceware.org Received: from mail-yi0-f41.google.com (HELO mail-yi0-f41.google.com) (209.85.218.41) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 09 Aug 2011 15:21:27 +0000 Received: by yib2 with SMTP id 2so84844yib.0 for ; Tue, 09 Aug 2011 08:21:27 -0700 (PDT) Received: by 10.142.88.12 with SMTP id l12mr5911751wfb.337.1312903286738; Tue, 09 Aug 2011 08:21:26 -0700 (PDT) Received: from localhost.localdomain ([203.110.240.178]) by mx.google.com with ESMTPS id s9sm46202pbk.66.2011.08.09.08.21.22 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 09 Aug 2011 08:21:26 -0700 (PDT) From: Sanjoy Das To: gdb-patches@sourceware.org Cc: Sanjoy Das Subject: [PATCH 5/7] Add a proxy unwinder. Date: Tue, 09 Aug 2011 15:21:00 -0000 Message-Id: <1312903509-25132-6-git-send-email-sanjoy@playingwithpointers.com> In-Reply-To: <1312903509-25132-1-git-send-email-sanjoy@playingwithpointers.com> References: <1312903509-25132-1-git-send-email-sanjoy@playingwithpointers.com> X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2011-08/txt/msg00189.txt.bz2 Have the proxy unwinder pass down all calls to the functions the JIT reader provides. --- gdb/ChangeLog | 9 +++ gdb/jit.c | 191 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ gdb/jit.h | 6 ++ 3 files changed, 206 insertions(+), 0 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index bd63356..2556be7 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,14 @@ 2011-08-09 Sanjoy Das + * jit.c (jut_unwind_reg_set_impl, free_reg_value_impl) + (jit_unwind_reg_get_impl, jit_frame_sniffer) + (jit_frame_unwind_stop_reason, jit_frame_this_id) + (jit_frame_prev_register, jit_dealloc_cache) + (jit_prepend_unwinder): New functions + * jit.h (jit_prepend_unwinder): New function + +2011-08-09 Sanjoy Das + * jit.c (add_objfile_entry, jit_target_read_impl) (jit_object_open_impl, jit_symtab_open_impl, compare_block) (jit_block_open_impl, jit_block_open_impl) diff --git a/gdb/jit.c b/gdb/jit.c index e81a386..58c3149 100644 --- a/gdb/jit.c +++ b/gdb/jit.c @@ -31,6 +31,7 @@ #include "inferior.h" #include "observer.h" #include "objfiles.h" +#include "regcache.h" #include "symfile.h" #include "symtab.h" #include "target.h" @@ -843,6 +844,190 @@ jit_breakpoint_re_set_internal (struct gdbarch *gdbarch, return 0; } +/* The private data passed around in the frame unwind callback + functions. */ +struct jit_unwind_private +{ + /* Cached register values. See jit_frame_sniffer to see how this + works. */ + struct gdb_reg_value **registers; + /* The frame being unwound. */ + struct frame_info *this_frame; +}; + +static void +jit_unwind_reg_set_impl (struct gdb_unwind_callbacks *cb, int regnum, + struct gdb_reg_value *value) +{ + struct jit_unwind_private *priv = cb->priv_data; + int gdb_reg = gdbarch_dwarf2_reg_to_regnum (target_gdbarch, regnum); + gdb_assert (priv->registers); + priv->registers[gdb_reg] = value; +} + +static void +free_reg_value_impl (struct gdb_reg_value *reg_value) +{ + free (reg_value); +} + +static struct gdb_reg_value * +jit_unwind_reg_get_impl (struct gdb_unwind_callbacks *cb, int regnum) +{ + struct jit_unwind_private *priv = cb->priv_data; + int gdb_reg = gdbarch_dwarf2_reg_to_regnum (target_gdbarch, regnum); + int size = register_size (target_gdbarch, gdb_reg); + struct gdb_reg_value *value = malloc (sizeof (struct gdb_reg_value) + + size - 1); + value->defined = frame_register_read (priv->this_frame, gdb_reg, + value->value); + value->size = size; + value->free = free_reg_value_impl; + return value; +} + +/* The frame sniffer for the pseudo unwinder. + + While this is nominally a frame sniffer, in the case where the JIT + reader actually recognizes the frame, it does a lot more work -- it + unwinds the frame and saves the corresponding register values in + the cache. jit_frame_prev_register simply returns the saved + register values. */ +static int +jit_frame_sniffer (const struct frame_unwind *self, + struct frame_info *this_frame, void **cache) +{ + struct jit_inferior_data *inf_data = get_jit_inferior_data (); + struct jit_unwind_private *priv_data; + struct jit_dbg_reader *iter; + struct gdb_unwind_callbacks callbacks = + { + jit_unwind_reg_get_impl, + jit_unwind_reg_set_impl, + jit_target_read_impl + }; + struct gdb_reader_funcs *funcs; + + if (loaded_jit_reader == NULL) + return 0; + funcs = loaded_jit_reader->functions; + + if (!*cache) + { + *cache = XZALLOC (struct jit_unwind_private); + priv_data = *cache; + priv_data->registers = XCALLOC (gdbarch_num_regs (target_gdbarch), + struct gdb_reg_value *); + priv_data->this_frame = this_frame; + } + else + { + priv_data = *cache; + priv_data->this_frame = this_frame; + } + + callbacks.priv_data = priv_data; + + /* Try to coax the provided unwinder to unwind the stack */ + if (funcs->unwind (funcs, &callbacks) == GDB_SUCCESS) + { + if (jit_debug) + fprintf_unfiltered (gdb_stdlog, "Successfully unwound frame using " + "JIT reader.\n"); + return 1; + } + if (jit_debug) + fprintf_unfiltered (gdb_stdlog, "Could not unwind frame using " + "JIT reader.\n"); + + xfree (priv_data->registers); + xfree (priv_data); + *cache = NULL; + + return 0; +} + +static enum unwind_stop_reason +jit_frame_unwind_stop_reason (struct frame_info *this_frame, void **cache) +{ + return UNWIND_NO_REASON; +} + +static void +jit_frame_this_id (struct frame_info *this_frame, void **cache, + struct frame_id *this_id) +{ + struct jit_unwind_private private = + { + NULL, + this_frame + }; + struct gdb_frame_id frame_id; + struct gdb_reader_funcs *funcs; + struct gdb_unwind_callbacks callbacks = + { + jit_unwind_reg_get_impl, + NULL, + jit_target_read_impl, + + &private + }; + + gdb_assert (loaded_jit_reader); + funcs = loaded_jit_reader->functions; + + frame_id = funcs->get_frame_id (funcs, &callbacks); + *this_id = frame_id_build (frame_id.stack_address, frame_id.code_address); +} + +static struct value * +jit_frame_prev_register (struct frame_info *this_frame, void **cache, int reg) +{ + struct jit_unwind_private *priv = *cache; + struct gdb_reg_value *value; + + if (priv == NULL) + return frame_unwind_got_optimized (this_frame, reg); + + gdb_assert (priv->registers); + value = priv->registers[reg]; + if (value && value->defined) + return frame_unwind_got_bytes (this_frame, reg, value->value); + else + return frame_unwind_got_optimized (this_frame, reg); +} + +/* gdb_reg_value has a free function, which must be called on each + saved register value. */ +static void +jit_dealloc_cache (struct frame_info *this_frame, void *cache) +{ + struct jit_unwind_private *priv_data = cache; + int i; + + gdb_assert (priv_data->registers); + + for (i = 0; i < gdbarch_num_regs (target_gdbarch); i++) + if (priv_data->registers[i] && priv_data->registers[i]->free) + priv_data->registers[i]->free (priv_data->registers[i]); + + xfree (priv_data->registers); + xfree (priv_data); +} + +/* Simply relays everything back to the unwinder registered by the JIT + debug info reader.*/ +static const struct frame_unwind jit_frame_unwind = +{ + NORMAL_FRAME, + jit_frame_unwind_stop_reason, + jit_frame_this_id, + jit_frame_prev_register, + NULL, + jit_frame_sniffer, + jit_dealloc_cache +}; + /* Register any already created translations. */ static void @@ -1010,6 +1195,12 @@ jit_event_handler (struct gdbarch *gdbarch) } } +void +jit_prepend_unwinder (struct gdbarch *gdbarch) +{ + frame_unwind_prepend_unwinder (gdbarch, &jit_frame_unwind); +} + /* Provide a prototype to silence -Wmissing-prototypes. */ extern void _initialize_jit (void); diff --git a/gdb/jit.h b/gdb/jit.h index 73a1414..29cd10d 100644 --- a/gdb/jit.h +++ b/gdb/jit.h @@ -80,4 +80,10 @@ extern void jit_breakpoint_re_set (void); extern void jit_event_handler (struct gdbarch *gdbarch); +/* Prepend the JIT unwinder GDBARCH's. Prepending adds negligible + overhead since this unwinder quickly fails if no JIT reader is + loaded. This also prevents other unwinders which depend on the BFD + field not being NULL from tripping. */ +extern void jit_prepend_unwinder (struct gdbarch *gdbarch); + #endif /* JIT_H */ -- 1.7.5.4