binutils-gdb/gdb/dummy-frame.h
Andrew Burgess 8bcb520897 gdb: Add default frame methods to gdbarch
Supply default gdbarch methods for gdbarch_dummy_id,
gdbarch_unwind_pc, and gdbarch_unwind_sp.  This patch doesn't actually
convert any targets to use these methods, and so, there will be no
user visible changes after this commit.

The implementations for default_dummy_id and default_unwind_sp are
fairly straight forward, these just take on the pattern used by most
targets.  Once these default methods are in place then most targets
will be able to switch over.

The implementation for default_unwind_pc is also fairly straight
forward, but maybe needs some explanation.

This patch has gone through a number of iterations:

  https://sourceware.org/ml/gdb-patches/2018-03/msg00165.html
  https://sourceware.org/ml/gdb-patches/2018-03/msg00306.html
  https://sourceware.org/ml/gdb-patches/2018-06/msg00090.html
  https://sourceware.org/ml/gdb-patches/2018-09/msg00127.html

and the implementation of default_unwind_pc has changed over this
time.  Originally, I took an implementation like this:

    CORE_ADDR
    default_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
    {
      int pc_regnum = gdbarch_pc_regnum (gdbarch);
      return frame_unwind_register_unsigned (next_frame, pc_regnum);
    }

This is basically a clone of default_unwind_sp, but using $pc.  It was
pointed out that we could potentially do better, and in version 2 the
implementation became:

    CORE_ADDR
    default_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
    {
      struct type *type;
      int pc_regnum;
      CORE_ADDR addr;
      struct value *value;

      pc_regnum = gdbarch_pc_regnum (gdbarch);
      value = frame_unwind_register_value (next_frame, pc_regnum);
      type = builtin_type (gdbarch)->builtin_func_ptr;
      addr = extract_typed_address (value_contents_all (value), type);
      addr = gdbarch_addr_bits_remove (gdbarch, addr);
      release_value (value);
      value_free (value);
      return addr;
    }

The idea was to try split out some of the steps of unwinding the $pc,
steps that are on some (or many) targets no-ops, and so allow targets
that do override these methods, to make use of default_unwind_pc.

This implementation remained in place for version 2, 3, and 4.

However, I realised that I'd made a mistake, most targets simply use
frame_unwind_register_unsigned to unwind the $pc, and this throws an
error if the register value is optimized out or unavailable.  My new
proposed implementation doesn't do this, I was going to end up
breaking many targets.

I considered duplicating the code from frame_unwind_register_unsigned
that throws the errors into my new default_unwind_pc, however, this
felt really overly complex.  So, what I instead went with was to
simply revert back to using frame_unwind_register_unsigned.  Almost
all existing targets already use this. Some of the ones that don't can
be converted to, which means almost all targets could end up using the
default.

One addition I have made over the version 1 implementation is to add a
call to gdbarch_addr_bits_remove.  For most targets this is a no-op,
but for a handful, having this call in place will mean that they can
use the default method.  After all this, the new default_unwind_pc now
looks like this:

    CORE_ADDR
    default_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
    {
      int pc_regnum = gdbarch_pc_regnum (gdbarch);
      CORE_ADDR pc = frame_unwind_register_unsigned (next_frame, pc_regnum);
      pc = gdbarch_addr_bits_remove (gdbarch, pc);
      return pc;
    }

gdb/ChangeLog:

	* gdb/dummy-frame.c (default_dummy_id): Defined new function.
	* gdb/dummy-frame.h (default_dummy_id): Declare new function.
	* gdb/frame-unwind.c (default_unwind_pc): Define new function.
	(default_unwind_sp): Define new function.
	* gdb/frame-unwind.h (default_unwind_pc): Declare new function.
	(default_unwind_sp): Declare new function.
	* gdb/frame.c (frame_unwind_pc): Assume gdbarch_unwind_pc is
	available.
	(get_frame_sp): Assume that gdbarch_unwind_sp is available.
	* gdb/gdbarch.c: Regenerate.
	* gdb/gdbarch.h: Regenerate.
	* gdb/gdbarch.sh: Update definition of dummy_id, unwind_pc, and
	unwind_sp.  Add additional header files to be included in
	generated file.
2018-12-19 20:59:38 +00:00

83 lines
3.2 KiB
C

/* Code dealing with dummy stack frames, for GDB, the GNU debugger.
Copyright (C) 2002-2018 Free Software Foundation, Inc.
This file is part of GDB.
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 <http://www.gnu.org/licenses/>. */
#if !defined (DUMMY_FRAME_H)
#define DUMMY_FRAME_H 1
#include "frame.h"
struct infcall_suspend_state;
struct frame_unwind;
/* Push the information needed to identify, and unwind from, a dummy
frame onto the dummy frame stack. */
/* NOTE: cagney/2004-08-02: In the case of ABIs using push_dummy_code
containing more than one instruction, this interface many need to
be expanded so that it knowns the lower/upper extent of the dummy
frame's code. */
extern void dummy_frame_push (infcall_suspend_state *caller_state,
const frame_id *dummy_id,
thread_info *thread);
/* Pop the dummy frame DUMMY_ID, restoring program state to that before the
frame was created.
On return reinit_frame_cache has been called.
If the frame isn't found, flag an internal error.
NOTE: This can only pop the one frame, even if it is in the middle of the
stack, because the other frames may be for different threads, and there's
currently no way to tell which stack frame is for which thread. */
extern void dummy_frame_pop (frame_id dummy_id, thread_info *thread);
extern void dummy_frame_discard (frame_id dummy_id, thread_info *thread);
/* If the PC falls in a dummy frame, return a dummy frame
unwinder. */
extern const struct frame_unwind dummy_frame_unwind;
/* Destructor for dummy_frame. DATA is supplied by registrant.
REGISTERS_VALID is 1 for dummy_frame_pop, 0 for dummy_frame_discard. */
typedef void (dummy_frame_dtor_ftype) (void *data, int registers_valid);
/* Call DTOR with DTOR_DATA when DUMMY_ID frame of thread THREAD gets
discarded. Dummy frame with DUMMY_ID must exist. Multiple
destructors may be registered, they will be called in the reverse
order of registrations (LIFO). */
extern void register_dummy_frame_dtor (frame_id dummy_id,
thread_info *thread,
dummy_frame_dtor_ftype *dtor,
void *dtor_data);
/* Return 1 if there exists any dummy frame with any of its registered
destructors equal to both DTOR and DTOR_DATA. Return 0 otherwise. */
extern int find_dummy_frame_dtor (dummy_frame_dtor_ftype *dtor,
void *dtor_data);
/* Default implementation of gdbarch_dummy_id. Generate a dummy frame_id
for THIS_FRAME assuming that the frame is a dummy frame. */
extern struct frame_id default_dummy_id (struct gdbarch *gdbarch,
struct frame_info *this_frame);
#endif /* !defined (DUMMY_FRAME_H) */