From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 17855 invoked by alias); 5 May 2011 15:18:33 -0000 Received: (qmail 17828 invoked by uid 22791); 5 May 2011 15:18:28 -0000 X-SWARE-Spam-Status: No, hits=-1.9 required=5.0 tests=AWL,BAYES_00,TW_XF,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from sibelius.xs4all.nl (HELO glazunov.sibelius.xs4all.nl) (83.163.83.176) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 05 May 2011 15:18:10 +0000 Received: from glazunov.sibelius.xs4all.nl (kettenis@localhost [127.0.0.1]) by glazunov.sibelius.xs4all.nl (8.14.3/8.14.3) with ESMTP id p45FHnaf009931; Thu, 5 May 2011 17:17:50 +0200 (CEST) Received: (from kettenis@localhost) by glazunov.sibelius.xs4all.nl (8.14.3/8.14.3/Submit) id p45FHmxo012630; Thu, 5 May 2011 17:17:48 +0200 (CEST) Date: Thu, 05 May 2011 15:18:00 -0000 Message-Id: <201105051517.p45FHmxo012630@glazunov.sibelius.xs4all.nl> From: Mark Kettenis To: guitton@adacore.com CC: gdb-patches@sourceware.org In-reply-to: <20110505151014.GD72917@adacore.com> (message from Jerome Guitton on Thu, 5 May 2011 17:10:14 +0200) Subject: Re: [RFA] Support for x86 on-stack trampolines References: <1304468424-2060-1-git-send-email-guitton@adacore.com> <201105041020.p44AKGt2025840@glazunov.sibelius.xs4all.nl> <20110504151723.GB64873@adacore.com> <201105041530.p44FUMhC015899@glazunov.sibelius.xs4all.nl> <20110505151014.GD72917@adacore.com> 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-05/txt/msg00134.txt.bz2 > Date: Thu, 5 May 2011 17:10:14 +0200 > From: Jerome Guitton > > Mark Kettenis (mark.kettenis@xs4all.nl): > > > Ah, it looks like I created some confusement. It is i386_find_insn() > > as a name that I object to; simply name that funcion i386_match_insn() > > and give it the old comment for i386_match_insn(), and I'm happy. > > That way you don't have to adjust any of its callers. > > > > i386_match_pattern() is fine as the name for the broken out code that > > matches only a single pattern. > > > Ah, OK, I was confused indeed. Patch updated! OK to apply? Yes, thanks! > gdb/ChangeLog: > > * i386-tdep.c (i386_in_stack_tramp_p, i386_stack_tramp_frame_sniffer): > New functions. > (i386_stack_tramp_frame_unwind): New static global. > (i386_match_pattern): New function, extracted from i386_match_insn. > (i386_match_insn): Use i386_match_pattern. > (i386_match_insn_block): New function. > (i386_tramp_chain_in_reg_insns) > (i386_tramp_chain_on_stack_insns): New static variables. > (i386_gdbarch_init): Add i386_stack_tramp_frame_unwind to list > of unwinders. > > diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c > index 5f4089b..b2b7412 100644 > --- a/gdb/i386-tdep.c > +++ b/gdb/i386-tdep.c > @@ -1126,47 +1126,93 @@ struct i386_insn > gdb_byte mask[I386_MAX_MATCHED_INSN_LEN]; > }; > > -/* Search for the instruction at PC in the list SKIP_INSNS. Return > - the first instruction description that matches. Otherwise, return > - NULL. */ > +/* Return whether instruction at PC matches PATTERN. */ > > -static struct i386_insn * > -i386_match_insn (CORE_ADDR pc, struct i386_insn *skip_insns) > +static int > +i386_match_pattern (CORE_ADDR pc, struct i386_insn pattern) > { > - struct i386_insn *insn; > gdb_byte op; > > if (target_read_memory (pc, &op, 1)) > - return NULL; > + return 0; > > - for (insn = skip_insns; insn->len > 0; insn++) > + if ((op & pattern.mask[0]) == pattern.insn[0]) > { > - if ((op & insn->mask[0]) == insn->insn[0]) > - { > - gdb_byte buf[I386_MAX_MATCHED_INSN_LEN - 1]; > - int insn_matched = 1; > - size_t i; > - > - gdb_assert (insn->len > 1); > - gdb_assert (insn->len <= I386_MAX_MATCHED_INSN_LEN); > + gdb_byte buf[I386_MAX_MATCHED_INSN_LEN - 1]; > + int insn_matched = 1; > + size_t i; > > - if (target_read_memory (pc + 1, buf, insn->len - 1)) > - return NULL; > + gdb_assert (pattern.len > 1); > + gdb_assert (pattern.len <= I386_MAX_MATCHED_INSN_LEN); > > - for (i = 1; i < insn->len; i++) > - { > - if ((buf[i - 1] & insn->mask[i]) != insn->insn[i]) > - insn_matched = 0; > - } > + if (target_read_memory (pc + 1, buf, pattern.len - 1)) > + return 0; > > - if (insn_matched) > - return insn; > + for (i = 1; i < pattern.len; i++) > + { > + if ((buf[i - 1] & pattern.mask[i]) != pattern.insn[i]) > + insn_matched = 0; > } > + return insn_matched; > + } > + return 0; > +} > + > +/* Search for the instruction at PC in the list INSN_PATTERNS. Return > + the first instruction description that matches. Otherwise, return > + NULL. */ > + > +static struct i386_insn * > +i386_match_insn (CORE_ADDR pc, struct i386_insn *insn_patterns) > +{ > + struct i386_insn *pattern; > + > + for (pattern = insn_patterns; pattern->len > 0; pattern++) > + { > + if (i386_match_pattern (pc, *pattern)) > + return pattern; > } > > return NULL; > } > > +/* Return whether PC points inside a sequence of instructions that > + matches INSN_PATTERNS. */ > + > +static int > +i386_match_insn_block (CORE_ADDR pc, struct i386_insn *insn_patterns) > +{ > + CORE_ADDR current_pc; > + int ix, i; > + gdb_byte op; > + struct i386_insn *insn; > + > + insn = i386_match_insn (pc, insn_patterns); > + if (insn == NULL) > + return 0; > + > + current_pc = pc - insn->len; > + ix = insn - insn_patterns; > + for (i = ix - 1; i >= 0; i--) > + { > + if (!i386_match_pattern (current_pc, insn_patterns[i])) > + return 0; > + > + current_pc -= insn_patterns[i].len; > + } > + > + current_pc = pc + insn->len; > + for (insn = insn_patterns + ix + 1; insn->len > 0; insn++) > + { > + if (!i386_match_pattern (current_pc, *insn)) > + return 0; > + > + current_pc += insn->len; > + } > + > + return 1; > +} > + > /* Some special instructions that might be migrated by GCC into the > part of the prologue that sets up the new stack frame. Because the > stack frame hasn't been setup yet, no registers have been saved > @@ -1938,6 +1984,88 @@ static const struct frame_unwind i386_epilogue_frame_unwind = > }; > > > +/* Stack-based trampolines. */ > + > +/* These trampolines are used on cross x86 targets, when taking the > + address of a nested function. When executing these trampolines, > + no stack frame is set up, so we are in a similar situation as in > + epilogues and i386_epilogue_frame_this_id can be re-used. */ > + > +/* Static chain passed in register. */ > + > +struct i386_insn i386_tramp_chain_in_reg_insns[] = > +{ > + /* `movl imm32, %eax' and `movl imm32, %ecx' */ > + { 5, { 0xb8 }, { 0xfe } }, > + > + /* `jmp imm32' */ > + { 5, { 0xe9 }, { 0xff } }, > + > + {0} > +}; > + > +/* Static chain passed on stack (when regparm=3). */ > + > +struct i386_insn i386_tramp_chain_on_stack_insns[] = > +{ > + /* `push imm32' */ > + { 5, { 0x68 }, { 0xff } }, > + > + /* `jmp imm32' */ > + { 5, { 0xe9 }, { 0xff } }, > + > + {0} > +}; > + > +/* Return whether PC points inside a stack trampoline. */ > + > +static int > +i386_in_stack_tramp_p (struct gdbarch *gdbarch, CORE_ADDR pc) > +{ > + gdb_byte insn; > + char *name; > + > + /* A stack trampoline is detected if no name is associated > + to the current pc and if it points inside a trampoline > + sequence. */ > + > + find_pc_partial_function (pc, &name, NULL, NULL); > + if (name) > + return 0; > + > + if (target_read_memory (pc, &insn, 1)) > + return 0; > + > + if (!i386_match_insn_block (pc, i386_tramp_chain_in_reg_insns) > + && !i386_match_insn_block (pc, i386_tramp_chain_on_stack_insns)) > + return 0; > + > + return 1; > +} > + > +static int > +i386_stack_tramp_frame_sniffer (const struct frame_unwind *self, > + struct frame_info *this_frame, > + void **this_prologue_cache) > +{ > + if (frame_relative_level (this_frame) == 0) > + return i386_in_stack_tramp_p (get_frame_arch (this_frame), > + get_frame_pc (this_frame)); > + else > + return 0; > +} > + > +static const struct frame_unwind i386_stack_tramp_frame_unwind = > +{ > + NORMAL_FRAME, > + i386_epilogue_frame_unwind_stop_reason, > + i386_epilogue_frame_this_id, > + i386_frame_prev_register, > + NULL, > + i386_stack_tramp_frame_sniffer > +}; > + > + > /* Signal trampolines. */ > > static struct i386_frame_cache * > @@ -7295,6 +7423,7 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) > tdep->mm0_regnum = -1; > > /* Hook in the legacy prologue-based unwinders last (fallback). */ > + frame_unwind_append_unwinder (gdbarch, &i386_stack_tramp_frame_unwind); > frame_unwind_append_unwinder (gdbarch, &i386_sigtramp_frame_unwind); > frame_unwind_append_unwinder (gdbarch, &i386_frame_unwind); > >