gdb/gdb-archer.patch
Jan Kratochvil 48cf710500 Rebase to FSF GDB 7.2.50.20110320 (which is a 7.3 pre-release).
Merge archer-sergiodj-stap, the SystemTap probes breakpoints feature.
[stap] Fix -O2 warnings.
Fix Ada support crash on uninitialized gdbarch.
2011-03-20 21:44:20 +01:00

16407 lines
510 KiB
Diff
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

http://sourceware.org/gdb/wiki/ProjectArcher
http://sourceware.org/gdb/wiki/ArcherBranchManagement
GIT snapshot:
commit 6b2a0bf758263d22bf2b3bd2e02665cf0c24b0be
branch `archer' - the merge of branches:
archer-jankratochvil-vla
archer-jankratochvil-watchpoint3
archer-jankratochvil-ifunc
archer-tromey-python
archer-sergiodj-stap
#TODO?:archer-tromey-optional-psymtab (cherry-picked from post-7.2 master)
#TODO?:archer-tromey-threaded-dwarf
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 21ec38f..50c1272 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -1476,6 +1476,13 @@ enum
Tag_compatibility = 32
};
+struct sdt_note
+{
+ struct sdt_note *next;
+ bfd_size_type size;
+ bfd_byte data[1];
+};
+
/* Some private data is stashed away for future use using the tdata pointer
in the bfd structure. */
@@ -1633,6 +1640,8 @@ struct elf_obj_tdata
bfd_size_type build_id_size;
bfd_byte *build_id;
+ struct sdt_note *sdt_note_head;
+
/* True if the bfd contains symbols that have the STT_GNU_IFUNC
symbol type. Used to set the osabi field in the ELF header
structure. */
diff --git a/bfd/elf.c b/bfd/elf.c
index f69abf2..3c038eb 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -8416,6 +8416,37 @@ elfobj_grok_gnu_note (bfd *abfd, Elf_Internal_Note *note)
}
}
+#define SDT_NOTE_TYPE 3
+
+static bfd_boolean
+elfobj_grok_stapsdt_note_1 (bfd *abfd, Elf_Internal_Note *note)
+{
+ struct sdt_note *cur =
+ (struct sdt_note *) bfd_alloc (abfd, sizeof (struct sdt_note)
+ + note->descsz);
+
+ cur->next = (struct sdt_note *) (elf_tdata (abfd))->sdt_note_head;
+ cur->size = (bfd_size_type) note->descsz;
+ memcpy (cur->data, note->descdata, note->descsz);
+
+ elf_tdata (abfd)->sdt_note_head = cur;
+
+ return TRUE;
+}
+
+static bfd_boolean
+elfobj_grok_stapsdt_note (bfd *abfd, Elf_Internal_Note *note)
+{
+ switch (note->type)
+ {
+ case SDT_NOTE_TYPE:
+ return elfobj_grok_stapsdt_note_1 (abfd, note);
+
+ default:
+ return TRUE;
+ }
+}
+
static bfd_boolean
elfcore_netbsd_get_lwpid (Elf_Internal_Note *note, int *lwpidp)
{
@@ -9189,6 +9220,12 @@ elf_parse_notes (bfd *abfd, char *buf, size_t size, file_ptr offset)
if (! elfobj_grok_gnu_note (abfd, &in))
return FALSE;
}
+ else if (in.namesz == sizeof "stapsdt"
+ && strcmp (in.namedata, "stapsdt") == 0)
+ {
+ if (! elfobj_grok_stapsdt_note (abfd, &in))
+ return FALSE;
+ }
break;
}
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 489b1e9..c332b1b 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -716,8 +716,8 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
sentinel-frame.c \
serial.c ser-base.c ser-unix.c \
solib.c solib-target.c source.c \
- stabsread.c stack.c std-regs.c symfile.c symfile-mem.c symmisc.c \
- symtab.c \
+ stabsread.c stack.c stap-probe.c std-regs.c \
+ symfile.c symfile-mem.c symmisc.c symtab.c \
target.c target-descriptions.c target-memory.c \
thread.c top.c tracepoint.c \
trad-frame.c \
@@ -801,7 +801,8 @@ annotate.h sim-regno.h dictionary.h dfp.h main.h frame-unwind.h \
remote-fileio.h i386-linux-tdep.h vax-tdep.h objc-lang.h \
sentinel-frame.h bcache.h symfile.h windows-tdep.h linux-tdep.h \
gdb_usleep.h jit.h xml-syscall.h microblaze-tdep.h \
-psymtab.h psympriv.h progspace.h bfin-tdep.h ia64-hpux-tdep.h
+psymtab.h psympriv.h progspace.h bfin-tdep.h ia64-hpux-tdep.h \
+python/python.h python/python-internal.h
# Header files that already have srcdir in them, or which are in objdir.
@@ -886,7 +887,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
prologue-value.o memory-map.o memrange.o xml-support.o xml-syscall.o \
target-descriptions.o target-memory.o xml-tdesc.o xml-builtin.o \
inferior.o osdata.o gdb_usleep.o record.o gcore.o \
- jit.o progspace.o
+ jit.o progspace.o stap-probe.o
TSOBS = inflow.o
@@ -1307,6 +1308,12 @@ stamp-h: $(srcdir)/config.in config.status
CONFIG_LINKS= \
$(SHELL) config.status
+.gdbinit: $(srcdir)/gdbinit.in config.status
+ CONFIG_FILES=".gdbinit:gdbinit.in" \
+ CONFIG_COMMANDS= \
+ CONFIG_HEADERS= \
+ $(SHELL) config.status
+
config.status: $(srcdir)/configure configure.tgt configure.host
$(SHELL) config.status --recheck
diff --git a/gdb/NEWS b/gdb/NEWS
index feebf61..279a1c9 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -36,6 +36,10 @@
Initial support for the OpenCL C language (http://www.khronos.org/opencl)
has been integrated into GDB.
+* GDB now has support for SystemTap <sys/sdt.h> probes. You can set a
+ breakpoint using the new "probe:" linespec and inspect the probe
+ arguments using the new $_probe_arg family of convenience variables.
+
* Python scripting
** Parameters can now be be sub-classed in Python, and in particular
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index ed51ab0..6851810 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -11390,6 +11390,7 @@ ada_operator_length (const struct expression *exp, int pc, int *oplenp,
static int
ada_operator_check (struct expression *exp, int pos,
+ int (*type_func) (struct type *type, void *data),
int (*objfile_func) (struct objfile *objfile, void *data),
void *data)
{
@@ -11404,12 +11405,15 @@ ada_operator_check (struct expression *exp, int pos,
break;
default:
- return operator_check_standard (exp, pos, objfile_func, data);
+ return operator_check_standard (exp, pos, type_func, objfile_func,
+ data);
}
/* Invoke callbacks for TYPE and OBJFILE if they were set as non-NULL. */
- if (type && TYPE_OBJFILE (type)
+ if (type && type_func && (*type_func) (type, data))
+ return 1;
+ if (type && TYPE_OBJFILE (type) && objfile_func
&& (*objfile_func) (TYPE_OBJFILE (type), data))
return 1;
diff --git a/gdb/amd64-linux-nat.c b/gdb/amd64-linux-nat.c
index a869f85..c59daa0 100644
--- a/gdb/amd64-linux-nat.c
+++ b/gdb/amd64-linux-nat.c
@@ -265,18 +265,11 @@ amd64_linux_store_inferior_registers (struct target_ops *ops,
/* Support for debug registers. */
-static unsigned long amd64_linux_dr[DR_CONTROL + 1];
-
static unsigned long
-amd64_linux_dr_get (ptid_t ptid, int regnum)
+amd64_linux_dr_get (int tid, int regnum)
{
- int tid;
unsigned long value;
- tid = TIDGET (ptid);
- if (tid == 0)
- tid = PIDGET (ptid);
-
/* FIXME: kettenis/2001-03-27: Calling perror_with_name if the
ptrace call fails breaks debugging remote targets. The correct
way to fix this is to add the hardware breakpoint and watchpoint
@@ -298,14 +291,8 @@ amd64_linux_dr_get (ptid_t ptid, int regnum)
/* Set debug register REGNUM to VALUE in only the one LWP of PTID. */
static void
-amd64_linux_dr_set (ptid_t ptid, int regnum, unsigned long value)
+amd64_linux_dr_set (int tid, int regnum, unsigned long value)
{
- int tid;
-
- tid = TIDGET (ptid);
- if (tid == 0)
- tid = PIDGET (ptid);
-
errno = 0;
ptrace (PTRACE_POKEUSER, tid,
offsetof (struct user, u_debugreg[regnum]), value);
@@ -313,35 +300,96 @@ amd64_linux_dr_set (ptid_t ptid, int regnum, unsigned long value)
perror_with_name (_("Couldn't write debug register"));
}
-/* Set DR_CONTROL to ADDR in all LWPs of LWP_LIST. */
+/* Helper for amd64_linux_dr_set_control. */
+
+static void
+amd64_linux_dr_set_control_callback (int tid, void *control_voidp)
+{
+ unsigned long control = *(unsigned long *) control_voidp;
+
+ amd64_linux_dr_set (tid, DR_CONTROL, control);
+}
+
+static void amd64_linux_dr_set_addr (int regnum, CORE_ADDR addr);
+
+/* Set DR_CONTROL to ADDR in all LWPs of CURRENT_INFERIOR. */
static void
amd64_linux_dr_set_control (unsigned long control)
{
- struct lwp_info *lp;
- ptid_t ptid;
+ int inferior_pid = ptid_get_pid (inferior_ptid);
+ struct inferior *inf = current_inferior ();
+
+ /* Are we detaching breakpoints from a fork-ed child?
+ See linux_nat_iterate_watchpoint_lwps for the fork-ed child description.
+ The i386 counterpart is i386_linux_dr_set_control. */
+ if (inf->pid != inferior_pid)
+ {
+ struct i386_dr_mirror *dr_mirror = i386_dr_mirror_get ();
+ int i;
+
+ /* There were two changes in Linux kernel 2.6.33 by the commit:
+ 72f674d203cd230426437cdcf7dd6f681dad8b0d
+
+ (1) After fork/vfork/clone the new task no longer inherits the debug
+ registers. It has them zeroed instead. Either case is OK for GDB as
+ GDB already registers a fix up by linux_nat_set_new_thread.
+
+ (2) If you enable a breakpoint by the CONTROL bits you have already
+ written its ADDRESS. Otherwise Linux kernel will report EINVAL.
+ For this case the workaround here ensures that during resetting
+ (detaching) watchpoints for a fork-ed child we can set CONTROL
+ arbitrarily as the addresses get pre-set here just to be sure.
+
+ The second issue is hopefully going to be fixed in Linux kernel:
+ https://bugzilla.redhat.com/show_bug.cgi?id=660204 */
+
+ if (!dr_mirror->addr_preset)
+ {
+ dr_mirror->addr_preset = 1;
+
+ for (i = 0; i < DR_LASTADDR - DR_FIRSTADDR; i++)
+ amd64_linux_dr_set_addr (i, dr_mirror->addr[i]);
+ }
+ }
+
+ linux_nat_iterate_watchpoint_lwps (amd64_linux_dr_set_control_callback,
+ &control);
+}
+
+/* Helper for amd64_linux_dr_set_addr. */
+
+struct amd64_linux_dr_set_addr_data
+ {
+ int regnum;
+ CORE_ADDR addr;
+ };
+
+static void
+amd64_linux_dr_set_addr_callback (int tid, void *datap_voidp)
+{
+ const struct amd64_linux_dr_set_addr_data *datap = datap_voidp;
- amd64_linux_dr[DR_CONTROL] = control;
- ALL_LWPS (lp, ptid)
- amd64_linux_dr_set (ptid, DR_CONTROL, control);
+ amd64_linux_dr_set (tid, DR_FIRSTADDR + datap->regnum, datap->addr);
}
-/* Set address REGNUM (zero based) to ADDR in all LWPs of LWP_LIST. */
+/* Set address REGNUM (zero based) to ADDR in all LWPs of CURRENT_INFERIOR.
+ */
static void
amd64_linux_dr_set_addr (int regnum, CORE_ADDR addr)
{
- struct lwp_info *lp;
- ptid_t ptid;
+ struct amd64_linux_dr_set_addr_data data;
gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
- amd64_linux_dr[DR_FIRSTADDR + regnum] = addr;
- ALL_LWPS (lp, ptid)
- amd64_linux_dr_set (ptid, DR_FIRSTADDR + regnum, addr);
+ data.regnum = regnum;
+ data.addr = addr;
+ linux_nat_iterate_watchpoint_lwps (amd64_linux_dr_set_addr_callback, &data);
}
-/* Set address REGNUM (zero based) to zero in all LWPs of LWP_LIST. */
+/* Set address REGNUM (zero based) to zero in all LWPs of CURRENT_INFERIOR.
+ */
static void
amd64_linux_dr_reset_addr (int regnum)
@@ -354,37 +402,54 @@ amd64_linux_dr_reset_addr (int regnum)
static unsigned long
amd64_linux_dr_get_status (void)
{
- return amd64_linux_dr_get (inferior_ptid, DR_STATUS);
+ int tid;
+
+ tid = TIDGET (inferior_ptid);
+ if (tid == 0)
+ tid = PIDGET (inferior_ptid);
+
+ return amd64_linux_dr_get (tid, DR_STATUS);
}
-/* Unset MASK bits in DR_STATUS in all LWPs of LWP_LIST. */
+/* Helper for amd64_linux_dr_unset_status. */
static void
-amd64_linux_dr_unset_status (unsigned long mask)
+amd64_linux_dr_unset_status_callback (int tid, void *mask_voidp)
{
- struct lwp_info *lp;
- ptid_t ptid;
-
- ALL_LWPS (lp, ptid)
- {
- unsigned long value;
+ unsigned long mask = *(unsigned long *) mask_voidp;
+ unsigned long value;
- value = amd64_linux_dr_get (ptid, DR_STATUS);
- value &= ~mask;
- amd64_linux_dr_set (ptid, DR_STATUS, value);
- }
+ value = amd64_linux_dr_get (tid, DR_STATUS);
+ value &= ~mask;
+ amd64_linux_dr_set (tid, DR_STATUS, value);
}
+/* Unset MASK bits in DR_STATUS in all LWPs of CURRENT_INFERIOR. */
+
+static void
+amd64_linux_dr_unset_status (unsigned long mask)
+{
+ linux_nat_iterate_watchpoint_lwps (amd64_linux_dr_unset_status_callback,
+ &mask);
+}
static void
amd64_linux_new_thread (ptid_t ptid)
{
- int i;
+ struct i386_dr_mirror *dr_mirror = i386_dr_mirror_get ();
+ int i, tid;
+
+ /* Verify DR_MIRROR is valid. */
+ gdb_assert (PIDGET (ptid) == PIDGET (inferior_ptid));
+
+ tid = TIDGET (ptid);
+ if (tid == 0)
+ tid = PIDGET (ptid);
- for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
- amd64_linux_dr_set (ptid, i, amd64_linux_dr[i]);
+ for (i = 0; i < DR_LASTADDR - DR_FIRSTADDR; i++)
+ amd64_linux_dr_set (tid, DR_FIRSTADDR + i, dr_mirror->addr[i]);
- amd64_linux_dr_set (ptid, DR_CONTROL, amd64_linux_dr[DR_CONTROL]);
+ amd64_linux_dr_set (tid, DR_CONTROL, dr_mirror->control);
}
diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index d1736e1..3e54716 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -2001,7 +2001,8 @@ gen_expr (struct expression *exp, union exp_element **pc,
case OP_INTERNALVAR:
{
- const char *name = internalvar_name ((*pc)[1].internalvar);
+ struct internalvar *var = (*pc)[1].internalvar;
+ const char *name = internalvar_name (var);
struct trace_state_variable *tsv;
(*pc) += 3;
@@ -2015,7 +2016,7 @@ gen_expr (struct expression *exp, union exp_element **pc,
value->kind = axs_rvalue;
value->type = builtin_type (exp->gdbarch)->builtin_long_long;
}
- else
+ else if (! compile_internalvar_to_ax (var, ax, value))
error (_("$%s is not a trace state variable; GDB agent "
"expressions cannot use convenience variables."), name);
}
diff --git a/gdb/block.c b/gdb/block.c
index 776ae53..3544cf2 100644
--- a/gdb/block.c
+++ b/gdb/block.c
@@ -322,3 +322,21 @@ allocate_block (struct obstack *obstack)
return bl;
}
+
+/* Return OBJFILE in which BLOCK is located or NULL if we cannot find it for
+ whatever reason. */
+
+struct objfile *
+block_objfile (const struct block *block)
+{
+ struct symbol *func;
+
+ if (block == NULL)
+ return NULL;
+
+ func = block_linkage_function (block);
+ if (func == NULL)
+ return NULL;
+
+ return SYMBOL_SYMTAB (func)->objfile;
+}
diff --git a/gdb/block.h b/gdb/block.h
index 07d5bc7..fad89b1 100644
--- a/gdb/block.h
+++ b/gdb/block.h
@@ -167,4 +167,6 @@ extern const struct block *block_global_block (const struct block *block);
extern struct block *allocate_block (struct obstack *obstack);
+extern struct objfile *block_objfile (const struct block *block);
+
#endif /* BLOCK_H */
diff --git a/gdb/blockframe.c b/gdb/blockframe.c
index 5bc5930..3b546a7 100644
--- a/gdb/blockframe.c
+++ b/gdb/blockframe.c
@@ -163,6 +163,7 @@ static CORE_ADDR cache_pc_function_low = 0;
static CORE_ADDR cache_pc_function_high = 0;
static char *cache_pc_function_name = 0;
static struct obj_section *cache_pc_function_section = NULL;
+static int cache_pc_function_is_gnu_ifunc = 0;
/* Clear cache, e.g. when symbol table is discarded. */
@@ -173,6 +174,7 @@ clear_pc_function_cache (void)
cache_pc_function_high = 0;
cache_pc_function_name = (char *) 0;
cache_pc_function_section = NULL;
+ cache_pc_function_is_gnu_ifunc = 0;
}
/* Finds the "function" (text symbol) that is smaller than PC but
@@ -180,17 +182,19 @@ clear_pc_function_cache (void)
*NAME and/or *ADDRESS conditionally if that pointer is non-null.
If ENDADDR is non-null, then set *ENDADDR to be the end of the
function (exclusive), but passing ENDADDR as non-null means that
- the function might cause symbols to be read. This function either
- succeeds or fails (not halfway succeeds). If it succeeds, it sets
- *NAME, *ADDRESS, and *ENDADDR to real information and returns 1.
- If it fails, it sets *NAME, *ADDRESS, and *ENDADDR to zero and
- returns 0. */
+ the function might cause symbols to be read. If IS_GNU_IFUNC_P is provided
+ *IS_GNU_IFUNC_P is set to 1 on return if the function is STT_GNU_IFUNC.
+ This function either succeeds or fails (not halfway succeeds). If it
+ succeeds, it sets *NAME, *ADDRESS, and *ENDADDR to real information and
+ returns 1. If it fails, it sets *NAME, *ADDRESS, *ENDADDR and
+ *IS_GNU_IFUNC_P to zero and returns 0. */
/* Backward compatibility, no section argument. */
int
-find_pc_partial_function (CORE_ADDR pc, char **name, CORE_ADDR *address,
- CORE_ADDR *endaddr)
+find_pc_partial_function_gnu_ifunc (CORE_ADDR pc, char **name,
+ CORE_ADDR *address, CORE_ADDR *endaddr,
+ int *is_gnu_ifunc_p)
{
struct obj_section *section;
struct symbol *f;
@@ -240,6 +244,7 @@ find_pc_partial_function (CORE_ADDR pc, char **name, CORE_ADDR *address,
cache_pc_function_high = BLOCK_END (SYMBOL_BLOCK_VALUE (f));
cache_pc_function_name = SYMBOL_LINKAGE_NAME (f);
cache_pc_function_section = section;
+ cache_pc_function_is_gnu_ifunc = TYPE_GNU_IFUNC (SYMBOL_TYPE (f));
goto return_cached_value;
}
}
@@ -262,12 +267,15 @@ find_pc_partial_function (CORE_ADDR pc, char **name, CORE_ADDR *address,
*address = 0;
if (endaddr != NULL)
*endaddr = 0;
+ if (is_gnu_ifunc_p != NULL)
+ *is_gnu_ifunc_p = 0;
return 0;
}
cache_pc_function_low = SYMBOL_VALUE_ADDRESS (msymbol);
cache_pc_function_name = SYMBOL_LINKAGE_NAME (msymbol);
cache_pc_function_section = section;
+ cache_pc_function_is_gnu_ifunc = MSYMBOL_TYPE (msymbol) == mst_text_gnu_ifunc;
/* If the minimal symbol has a size, use it for the cache.
Otherwise use the lesser of the next minimal symbol in the same
@@ -330,9 +338,22 @@ find_pc_partial_function (CORE_ADDR pc, char **name, CORE_ADDR *address,
*endaddr = cache_pc_function_high;
}
+ if (is_gnu_ifunc_p)
+ *is_gnu_ifunc_p = cache_pc_function_is_gnu_ifunc;
+
return 1;
}
+/* See find_pc_partial_function_gnu_ifunc, only the IS_GNU_IFUNC_P parameter
+ is omitted here for backward API compatibility. */
+
+int
+find_pc_partial_function (CORE_ADDR pc, char **name, CORE_ADDR *address,
+ CORE_ADDR *endaddr)
+{
+ return find_pc_partial_function_gnu_ifunc (pc, name, address, endaddr, NULL);
+}
+
/* Return the innermost stack frame executing inside of BLOCK, or NULL
if there is no such frame. If BLOCK is NULL, just return NULL. */
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index c55e5c0..1a71cf8 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -62,6 +62,8 @@
#include "jit.h"
#include "xml-syscall.h"
#include "parser-defs.h"
+#include "gdb_regex.h"
+#include "stap-probe.h"
#include "cli/cli-utils.h"
/* readline include files */
@@ -106,6 +108,9 @@ static void break_command_1 (char *, int, int);
static void mention (struct breakpoint *);
+static struct bp_location *add_location_to_breakpoint (struct breakpoint *b,
+ const struct symtab_and_line *sal);
+
/* This function is used in gdbtk sources and thus can not be made
static. */
struct breakpoint *set_raw_breakpoint (struct gdbarch *gdbarch,
@@ -1158,6 +1163,25 @@ watchpoint_in_thread_scope (struct breakpoint *b)
&& !is_executing (inferior_ptid)));
}
+/* Set watchpoint B to disp_del_at_next_stop, even including its possible
+ associated bp_watchpoint_scope breakpoint. */
+
+static void
+watchpoint_del_at_next_stop (struct breakpoint *b)
+{
+ gdb_assert (is_watchpoint (b));
+
+ if (b->related_breakpoint != b)
+ {
+ gdb_assert (b->related_breakpoint->type == bp_watchpoint_scope);
+ gdb_assert (b->related_breakpoint->related_breakpoint == b);
+ b->related_breakpoint->disposition = disp_del_at_next_stop;
+ b->related_breakpoint->related_breakpoint = b->related_breakpoint;
+ b->related_breakpoint = b;
+ }
+ b->disposition = disp_del_at_next_stop;
+}
+
/* Assuming that B is a watchpoint:
- Reparse watchpoint expression, if REPARSE is non-zero
- Evaluate expression and store the result in B->val
@@ -1217,12 +1241,17 @@ update_watchpoint (struct breakpoint *b, int reparse)
struct frame_id saved_frame_id;
int frame_saved;
+ gdb_assert (is_watchpoint (b));
+
/* If this is a local watchpoint, we only want to check if the
watchpoint frame is in scope if the current thread is the thread
that was used to create the watchpoint. */
if (!watchpoint_in_thread_scope (b))
return;
+ if (b->pspace != current_program_space)
+ return;
+
if (b->disposition == disp_del_at_next_stop)
return;
@@ -1452,13 +1481,7 @@ update_watchpoint (struct breakpoint *b, int reparse)
Watchpoint %d deleted because the program has left the block\n\
in which its expression is valid.\n"),
b->number);
- if (b->related_breakpoint)
- {
- b->related_breakpoint->disposition = disp_del_at_next_stop;
- b->related_breakpoint->related_breakpoint = NULL;
- b->related_breakpoint= NULL;
- }
- b->disposition = disp_del_at_next_stop;
+ watchpoint_del_at_next_stop (b);
}
/* Restore the selected frame. */
@@ -1500,6 +1523,24 @@ should_be_inserted (struct bp_location *bl)
return 1;
}
+/* Set or clear a SystemTap semaphore. ARCH is the target
+ architecture; ADDRESS is the address of the semaphore, and SETTING
+ is either zero or one. */
+
+static void
+modify_semaphore (struct gdbarch *arch, CORE_ADDR address, int setting)
+{
+ gdb_byte bytes[sizeof (LONGEST)];
+ /* The ABI specifies "unsigned short". */
+ struct type *type = builtin_type (arch)->builtin_unsigned_short;
+
+ store_unsigned_integer (bytes, TYPE_LENGTH (type),
+ gdbarch_byte_order (arch), setting);
+
+ /* Ignore errors. FIXME. */
+ target_write_memory (address, bytes, TYPE_LENGTH (type));
+}
+
/* Insert a low-level "breakpoint" of some type. BL is the breakpoint
location. Any error messages are printed to TMP_ERROR_STREAM; and
DISABLED_BREAKS, and HW_BREAKPOINT_ERROR are used to report problems.
@@ -1595,6 +1636,9 @@ insert_bp_location (struct bp_location *bl,
else
val = target_insert_breakpoint (bl->gdbarch,
&bl->target_info);
+
+ if (bl->semaphore != 0)
+ modify_semaphore (bl->gdbarch, bl->semaphore, 1);
}
else
{
@@ -1849,6 +1893,7 @@ insert_breakpoint_locations (void)
int val = 0;
int disabled_breaks = 0;
int hw_breakpoint_error = 0;
+ struct program_space *saved_current_program_space = current_program_space;
struct ui_file *tmp_error_stream = mem_fileopen ();
struct cleanup *cleanups = make_cleanup_ui_file_delete (tmp_error_stream);
@@ -1876,9 +1921,13 @@ insert_breakpoint_locations (void)
/* For targets that support global breakpoints, there's no need
to select an inferior to insert breakpoint to. In fact, even
if we aren't attached to any process yet, we should still
- insert breakpoints. */
+ insert breakpoints.
+
+ Also inserting breakpoints into inappropriate inferior must be
+ prevented. */
if (!gdbarch_has_global_breakpoints (target_gdbarch)
- && ptid_equal (inferior_ptid, null_ptid))
+ && (ptid_equal (inferior_ptid, null_ptid)
+ || bl->pspace != saved_current_program_space))
continue;
val = insert_bp_location (bl, tmp_error_stream, &disabled_breaks,
@@ -1902,13 +1951,19 @@ insert_breakpoint_locations (void)
if (bpt->disposition == disp_del_at_next_stop)
continue;
-
+
for (loc = bpt->loc; loc; loc = loc->next)
- if (!loc->inserted && should_be_inserted (loc))
- {
- some_failed = 1;
- break;
- }
+ {
+ /* Verify the first loop above really tried to insert this LOC. */
+ if (!loc->inserted && should_be_inserted (loc)
+ && (gdbarch_has_global_breakpoints (target_gdbarch)
+ || (!ptid_equal (inferior_ptid, null_ptid)
+ && loc->pspace == saved_current_program_space)))
+ {
+ some_failed = 1;
+ break;
+ }
+ }
if (some_failed)
{
for (loc = bpt->loc; loc; loc = loc->next)
@@ -2090,15 +2145,24 @@ struct breakpoint_objfile_data
/* Minimal symbol(s) for "longjmp", "siglongjmp", etc. (if any). */
struct minimal_symbol *longjmp_msym[NUM_LONGJMP_NAMES];
+ /* SystemTap probe point for longjmp (if any). */
+ const struct stap_probe *longjmp_probe;
+
/* Minimal symbol for "std::terminate()" (if any). */
struct minimal_symbol *terminate_msym;
/* Minimal symbol for "_Unwind_DebugHook" (if any). */
struct minimal_symbol *exception_msym;
+
+ /* SystemTap probe point for unwinding (if any). */
+ const struct stap_probe *exception_probe;
};
static const struct objfile_data *breakpoint_objfile_key;
+/* SystemTap probe not found sentinel. */
+static const struct stap_probe probe_not_found;
+
/* Minimal symbol not found sentinel. */
static struct minimal_symbol msym_not_found;
@@ -2206,6 +2270,29 @@ create_longjmp_master_breakpoint (void)
bp_objfile_data = get_breakpoint_objfile_data (objfile);
+ if (bp_objfile_data->longjmp_probe != &probe_not_found)
+ {
+ if (bp_objfile_data->longjmp_probe == NULL)
+ bp_objfile_data->longjmp_probe
+ = find_probe_in_objfile (objfile, "libc", "longjmp");
+
+ if (bp_objfile_data->longjmp_probe)
+ {
+ struct breakpoint *b;
+ struct gdbarch *gdbarch = get_objfile_arch (objfile);
+
+ b = create_internal_breakpoint (gdbarch,
+ bp_objfile_data->longjmp_probe->address,
+ bp_longjmp_master);
+ b->addr_string = xstrdup ("probe:libc:longjmp");
+ b->enable_state = bp_disabled;
+
+ continue;
+ }
+ else
+ bp_objfile_data->longjmp_probe = &probe_not_found;
+ }
+
for (i = 0; i < NUM_LONGJMP_NAMES; i++)
{
struct breakpoint *b;
@@ -2314,6 +2401,31 @@ create_exception_master_breakpoint (void)
bp_objfile_data = get_breakpoint_objfile_data (objfile);
+ /* We prefer the SystemTap probe point if it exists. */
+ if (bp_objfile_data->exception_probe != &probe_not_found)
+ {
+ if (bp_objfile_data->exception_probe == NULL)
+ bp_objfile_data->exception_probe
+ = find_probe_in_objfile (objfile, "libgcc", "unwind");
+
+ if (bp_objfile_data->exception_probe)
+ {
+ struct breakpoint *b;
+ struct gdbarch *gdbarch = get_objfile_arch (objfile);
+
+ b = create_internal_breakpoint (gdbarch,
+ bp_objfile_data->exception_probe->address,
+ bp_exception_master);
+ b->addr_string = xstrdup ("probe:libgcc:unwind");
+ b->enable_state = bp_disabled;
+ continue;
+ }
+ else
+ bp_objfile_data->exception_probe = &probe_not_found;
+ }
+
+ /* Otherwise, try the hook function. */
+
if (msym_not_found_p (bp_objfile_data->exception_msym))
continue;
@@ -2532,6 +2644,9 @@ remove_breakpoint_1 (struct bp_location *bl, insertion_state_t is)
val = target_remove_hw_breakpoint (bl->gdbarch, &bl->target_info);
else
val = target_remove_breakpoint (bl->gdbarch, &bl->target_info);
+
+ if (bl->semaphore != 0)
+ modify_semaphore (bl->gdbarch, bl->semaphore, 0);
}
else
{
@@ -3488,6 +3603,8 @@ print_it_typical (bpstat bs)
case bp_tracepoint:
case bp_fast_tracepoint:
case bp_jit_event:
+ case bp_gnu_ifunc_resolver:
+ case bp_gnu_ifunc_resolver_return:
default:
result = PRINT_UNKNOWN;
break;
@@ -3713,6 +3830,8 @@ watchpoint_check (void *p)
gdb_assert (bs->breakpoint_at != NULL);
b = bs->breakpoint_at;
+ gdb_assert (is_watchpoint (b));
+
/* If this is a local watchpoint, we only want to check if the
watchpoint frame is in scope if the current thread is the thread
that was used to create the watchpoint. */
@@ -3822,13 +3941,7 @@ watchpoint_check (void *p)
" deleted because the program has left the block in\n\
which its expression is valid.\n");
- if (b->related_breakpoint)
- {
- b->related_breakpoint->disposition = disp_del_at_next_stop;
- b->related_breakpoint->related_breakpoint = NULL;
- b->related_breakpoint = NULL;
- }
- b->disposition = disp_del_at_next_stop;
+ watchpoint_del_at_next_stop (b);
return WP_DELETED;
}
@@ -4033,9 +4146,7 @@ bpstat_check_watchpoint (bpstat bs)
case 0:
/* Error from catch_errors. */
printf_filtered (_("Watchpoint %d deleted.\n"), b->number);
- if (b->related_breakpoint)
- b->related_breakpoint->disposition = disp_del_at_next_stop;
- b->disposition = disp_del_at_next_stop;
+ watchpoint_del_at_next_stop (b);
/* We've already printed what needs to be printed. */
bs->print_it = print_it_done;
break;
@@ -4246,7 +4357,7 @@ bpstat_stop_status (struct address_space *aspace,
watchpoint as triggered so that we will handle the
out-of-scope event. We'll get to the watchpoint next
iteration. */
- if (b->type == bp_watchpoint_scope)
+ if (b->type == bp_watchpoint_scope && b->related_breakpoint != b)
b->related_breakpoint->watchpoint_triggered = watch_triggered_yes;
}
}
@@ -4368,7 +4479,7 @@ handle_jit_event (void)
/* Decide what infrun needs to do with this bpstat. */
struct bpstat_what
-bpstat_what (bpstat bs)
+bpstat_what (bpstat bs_head)
{
struct bpstat_what retval;
/* We need to defer calling `solib_add', as adding new symbols
@@ -4376,12 +4487,13 @@ bpstat_what (bpstat bs)
and hence may clear unprocessed entries in the BS chain. */
int shlib_event = 0;
int jit_event = 0;
+ bpstat bs;
retval.main_action = BPSTAT_WHAT_KEEP_CHECKING;
retval.call_dummy = STOP_NONE;
retval.is_longjmp = 0;
- for (; bs != NULL; bs = bs->next)
+ for (bs = bs_head; bs != NULL; bs = bs->next)
{
/* Extract this BS's action. After processing each BS, we check
if its action overrides all we've seem so far. */
@@ -4511,6 +4623,16 @@ bpstat_what (bpstat bs)
out already. */
internal_error (__FILE__, __LINE__,
_("bpstat_what: tracepoint encountered"));
+ break;
+ case bp_gnu_ifunc_resolver:
+ /* Step over it (and insert bp_gnu_ifunc_resolver_return). */
+ this_action = BPSTAT_WHAT_SINGLE;
+ break;
+ case bp_gnu_ifunc_resolver_return:
+ /* The breakpoint will be removed, execution will restart from the
+ PC of the former breakpoint. */
+ this_action = BPSTAT_WHAT_KEEP_CHECKING;
+ break;
default:
internal_error (__FILE__, __LINE__,
_("bpstat_what: unhandled bptype %d"), (int) bptype);
@@ -4519,6 +4641,9 @@ bpstat_what (bpstat bs)
retval.main_action = max (retval.main_action, this_action);
}
+ /* These operations may affect the bs->breakpoint_at state so they are
+ delayed after MAIN_ACTION is decided above. */
+
if (shlib_event)
{
if (debug_infrun)
@@ -4548,6 +4673,23 @@ bpstat_what (bpstat bs)
handle_jit_event ();
}
+ for (bs = bs_head; bs != NULL; bs = bs->next)
+ {
+ struct breakpoint *b = bs->breakpoint_at;
+
+ if (b == NULL)
+ continue;
+ switch (b->type)
+ {
+ case bp_gnu_ifunc_resolver:
+ gnu_ifunc_resolver_stop (b);
+ break;
+ case bp_gnu_ifunc_resolver_return:
+ gnu_ifunc_resolver_return_stop (b);
+ break;
+ }
+ }
+
return retval;
}
@@ -4703,6 +4845,8 @@ bptype_string (enum bptype type)
{bp_fast_tracepoint, "fast tracepoint"},
{bp_static_tracepoint, "static tracepoint"},
{bp_jit_event, "jit events"},
+ {bp_gnu_ifunc_resolver, "STT_GNU_IFUNC resolver"},
+ {bp_gnu_ifunc_resolver_return, "STT_GNU_IFUNC resolver return"},
};
if (((int) type >= (sizeof (bptypes) / sizeof (bptypes[0])))
@@ -4837,6 +4981,8 @@ print_one_breakpoint_location (struct breakpoint *b,
case bp_fast_tracepoint:
case bp_static_tracepoint:
case bp_jit_event:
+ case bp_gnu_ifunc_resolver:
+ case bp_gnu_ifunc_resolver_return:
if (opts.addressprint)
{
annotate_field (4);
@@ -5112,7 +5258,8 @@ user_settable_breakpoint (const struct breakpoint *b)
|| b->type == bp_catchpoint
|| b->type == bp_hardware_breakpoint
|| is_tracepoint (b)
- || is_watchpoint (b));
+ || is_watchpoint (b)
+ || b->type == bp_gnu_ifunc_resolver);
}
/* Return true if this breakpoint was set by the user, false if it is
@@ -5608,6 +5755,8 @@ allocate_bp_location (struct breakpoint *bpt)
case bp_longjmp_master:
case bp_std_terminate_master:
case bp_exception_master:
+ case bp_gnu_ifunc_resolver:
+ case bp_gnu_ifunc_resolver_return:
loc->loc_type = bp_loc_software_breakpoint;
break;
case bp_hardware_breakpoint:
@@ -5697,6 +5846,7 @@ set_raw_breakpoint_without_location (struct gdbarch *gdbarch,
b->ops = NULL;
b->condition_not_parsed = 0;
b->py_bp_object = NULL;
+ b->related_breakpoint = b;
/* Add this breakpoint to the end of the chain so that a list of
breakpoints will come out in order of increasing numbers. */
@@ -5713,9 +5863,12 @@ set_raw_breakpoint_without_location (struct gdbarch *gdbarch,
return b;
}
-/* Initialize loc->function_name. */
+/* Initialize loc->function_name. EXPLICIT_LOC says no indirect function
+ resolutions should be made as the user specified the location explicitly
+ enough. */
+
static void
-set_breakpoint_location_function (struct bp_location *loc)
+set_breakpoint_location_function (struct bp_location *loc, int explicit_loc)
{
gdb_assert (loc->owner != NULL);
@@ -5723,8 +5876,33 @@ set_breakpoint_location_function (struct bp_location *loc)
|| loc->owner->type == bp_hardware_breakpoint
|| is_tracepoint (loc->owner))
{
- find_pc_partial_function (loc->address, &(loc->function_name),
- NULL, NULL);
+ int is_gnu_ifunc;
+
+ find_pc_partial_function_gnu_ifunc (loc->address, &loc->function_name,
+ NULL, NULL, &is_gnu_ifunc);
+
+ if (is_gnu_ifunc && !explicit_loc)
+ {
+ struct breakpoint *b = loc->owner;
+
+ gdb_assert (loc->pspace == current_program_space);
+ if (gnu_ifunc_resolve_name (loc->function_name,
+ &loc->requested_address))
+ {
+ /* Recalculate ADDRESS based on new REQUESTED_ADDRESS. */
+ loc->address = adjust_breakpoint_address (loc->gdbarch,
+ loc->requested_address,
+ b->type);
+ }
+ else if (b->type == bp_breakpoint && b->loc == loc
+ && loc->next == NULL && b->related_breakpoint == b)
+ {
+ /* Create only the whole new breakpoint of this type but do not
+ mess more complicated breakpoints with multiple locations. */
+ b->type = bp_gnu_ifunc_resolver;
+ }
+ }
+
if (loc->function_name)
loc->function_name = xstrdup (loc->function_name);
}
@@ -5787,6 +5965,7 @@ set_raw_breakpoint (struct gdbarch *gdbarch,
b->loc->requested_address = sal.pc;
b->loc->address = adjusted_address;
b->loc->pspace = sal.pspace;
+ b->loc->semaphore = sal.semaphore;
/* Store the program space that was used to set the breakpoint, for
breakpoint resetting. */
@@ -5799,7 +5978,8 @@ set_raw_breakpoint (struct gdbarch *gdbarch,
b->loc->section = sal.section;
b->line_number = sal.line;
- set_breakpoint_location_function (b->loc);
+ set_breakpoint_location_function (b->loc,
+ sal.explicit_pc || sal.explicit_line);
breakpoints_changed ();
@@ -6916,13 +7096,14 @@ clone_momentary_breakpoint (struct breakpoint *orig)
copy = set_raw_breakpoint_without_location (orig->gdbarch, orig->type);
copy->loc = allocate_bp_location (copy);
- set_breakpoint_location_function (copy->loc);
+ set_breakpoint_location_function (copy->loc, 1);
copy->loc->gdbarch = orig->loc->gdbarch;
copy->loc->requested_address = orig->loc->requested_address;
copy->loc->address = orig->loc->address;
copy->loc->section = orig->loc->section;
copy->loc->pspace = orig->loc->pspace;
+ copy->loc->semaphore = orig->loc->semaphore;
if (orig->source_file == NULL)
copy->source_file = NULL;
@@ -7016,6 +7197,7 @@ mention (struct breakpoint *b)
do_cleanups (ui_out_chain);
break;
case bp_breakpoint:
+ case bp_gnu_ifunc_resolver:
if (ui_out_is_mi_like_p (uiout))
{
say_where = 0;
@@ -7026,6 +7208,8 @@ mention (struct breakpoint *b)
else
printf_filtered (_("Breakpoint"));
printf_filtered (_(" %d"), b->number);
+ if (b->type == bp_gnu_ifunc_resolver)
+ printf_filtered (_(" at gnu-indirect-function resolver"));
say_where = 1;
break;
case bp_hardware_breakpoint:
@@ -7085,6 +7269,7 @@ mention (struct breakpoint *b)
case bp_longjmp_master:
case bp_std_terminate_master:
case bp_exception_master:
+ case bp_gnu_ifunc_resolver_return:
break;
}
@@ -7142,10 +7327,12 @@ add_location_to_breakpoint (struct breakpoint *b,
loc->address = adjust_breakpoint_address (loc->gdbarch,
loc->requested_address, b->type);
loc->pspace = sal->pspace;
+ loc->semaphore = sal->semaphore;
gdb_assert (loc->pspace != NULL);
loc->section = sal->section;
- set_breakpoint_location_function (loc);
+ set_breakpoint_location_function (loc,
+ sal->explicit_pc || sal->explicit_line);
return loc;
}
@@ -8580,6 +8767,7 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
b = set_raw_breakpoint_without_location (NULL, bp_type);
set_breakpoint_number (internal, b);
b->thread = thread;
+ b->pspace = current_program_space;
b->disposition = disp_donttouch;
b->exp = exp;
b->exp_valid_block = exp_valid_block;
@@ -9742,6 +9930,9 @@ update_global_location_list (int should_insert)
int keep_in_target = 0;
int removed = 0;
+ if (old_loc->pspace != current_program_space)
+ continue;
+
/* Skip LOCP entries which will definitely never be needed.
Stop either at or being the one matching OLD_LOC. */
while (locp < bp_location + bp_location_count
@@ -10058,12 +10249,20 @@ delete_breakpoint (struct breakpoint *bpt)
/* At least avoid this stale reference until the reference counting
of breakpoints gets resolved. */
- if (bpt->related_breakpoint != NULL)
+ if (bpt->related_breakpoint != bpt)
{
- gdb_assert (bpt->related_breakpoint->related_breakpoint == bpt);
- bpt->related_breakpoint->disposition = disp_del_at_next_stop;
- bpt->related_breakpoint->related_breakpoint = NULL;
- bpt->related_breakpoint = NULL;
+ struct breakpoint *related;
+
+ if (bpt->type == bp_watchpoint_scope)
+ watchpoint_del_at_next_stop (bpt->related_breakpoint);
+ else if (bpt->related_breakpoint->type == bp_watchpoint_scope)
+ watchpoint_del_at_next_stop (bpt);
+
+ /* Unlink bpt from the bpt->related_breakpoint ring. */
+ for (related = bpt; related->related_breakpoint != bpt;
+ related = related->related_breakpoint);
+ related->related_breakpoint = bpt->related_breakpoint;
+ bpt->related_breakpoint = bpt;
}
observer_notify_breakpoint_deleted (bpt->number);
@@ -10376,7 +10575,7 @@ update_static_tracepoint (struct breakpoint *b, struct symtab_and_line sal)
return sal;
}
-static void
+void
update_breakpoint_locations (struct breakpoint *b,
struct symtabs_and_lines sals)
{
@@ -10508,6 +10707,7 @@ breakpoint_re_set_one (void *bint)
case bp_tracepoint:
case bp_fast_tracepoint:
case bp_static_tracepoint:
+ case bp_gnu_ifunc_resolver:
/* Do not attempt to re-set breakpoints disabled during startup. */
if (b->enable_state == bp_startup_disabled)
return 0;
@@ -10678,6 +10878,7 @@ breakpoint_re_set_one (void *bint)
case bp_exception:
case bp_exception_resume:
case bp_jit_event:
+ case bp_gnu_ifunc_resolver_return:
break;
}
@@ -10844,11 +11045,25 @@ map_breakpoint_numbers (char *args, void (*function) (struct breakpoint *,
ALL_BREAKPOINTS_SAFE (b, tmp)
if (b->number == num)
{
- struct breakpoint *related_breakpoint = b->related_breakpoint;
+ struct breakpoint *related_breakpoint;
+
match = 1;
- function (b, data);
- if (related_breakpoint)
- function (related_breakpoint, data);
+ related_breakpoint = b;
+ do
+ {
+ struct breakpoint *next_related_b;
+
+ /* FUNCTION can be also delete_breakpoint. */
+ next_related_b = related_breakpoint->related_breakpoint;
+ function (related_breakpoint, data);
+
+ /* For delete_breakpoint of the last entry of the ring we
+ were traversing we would never get back to B. */
+ if (next_related_b == related_breakpoint)
+ break;
+ related_breakpoint = next_related_b;
+ }
+ while (related_breakpoint != b);
break;
}
if (match == 0)
@@ -11979,6 +12194,24 @@ all_tracepoints (void)
return tp_vec;
}
+#if 0
+/* Call type_mark_used for any TYPEs referenced from this GDB source file. */
+
+static void
+breakpoint_types_mark_used (void)
+{
+ struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ {
+ if (b->exp)
+ exp_types_mark_used (b->exp);
+ if (b->val)
+ type_mark_used (value_type (b->val));
+ }
+}
+#endif
+
/* This help string is used for the break, hbreak, tbreak and thbreak
commands. It is defined as a macro to prevent duplication.
@@ -12598,4 +12831,7 @@ inferior in all-stop mode, gdb behaves as if always-inserted mode is off."),
automatic_hardware_breakpoints = 1;
observer_attach_about_to_proceed (breakpoint_about_to_proceed);
+#if 0
+ observer_attach_mark_used (breakpoint_types_mark_used);
+#endif
}
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index bd09713..587e3a1 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -149,6 +149,19 @@ enum bptype
/* Event for JIT compiled code generation or deletion. */
bp_jit_event,
+
+ /* Breakpoint is placed at the STT_GNU_IFUNC resolver. When hit GDB
+ inserts new bp_gnu_ifunc_resolver_return at the caller.
+ bp_gnu_ifunc_resolver is still being kept here as a different thread
+ may still hit it before bp_gnu_ifunc_resolver_return is hit by the
+ original thread. */
+ bp_gnu_ifunc_resolver,
+
+ /* On its hit GDB now know the resolved address of the target
+ STT_GNU_IFUNC function. Associated bp_gnu_ifunc_resolver can be
+ deleted now and the breakpoint moved to the target function entry
+ point. */
+ bp_gnu_ifunc_resolver_return,
};
/* States of enablement of breakpoint. */
@@ -345,6 +358,11 @@ struct bp_location
processor's architectual constraints. */
CORE_ADDR requested_address;
+ /* If the location comes from a SystemTap probe point, and the probe
+ has an associated semaphore variable, then this is the address of
+ the semaphore. Otherwise, this is zero. */
+ CORE_ADDR semaphore;
+
char *function_name;
/* Details of the placed breakpoint, when inserted. */
@@ -888,6 +906,9 @@ extern int breakpoint_thread_match (struct address_space *,
extern void until_break_command (char *, int, int);
+extern void update_breakpoint_locations (struct breakpoint *b,
+ struct symtabs_and_lines sals);
+
extern void breakpoint_re_set (void);
extern void breakpoint_re_set_thread (struct breakpoint *);
diff --git a/gdb/c-typeprint.c b/gdb/c-typeprint.c
index c70fa4b..6bc3397 100644
--- a/gdb/c-typeprint.c
+++ b/gdb/c-typeprint.c
@@ -626,9 +626,14 @@ c_type_print_varspec_suffix (struct type *type,
fprintf_filtered (stream, ")");
fprintf_filtered (stream, "[");
- if (get_array_bounds (type, &low_bound, &high_bound))
- fprintf_filtered (stream, "%d",
- (int) (high_bound - low_bound + 1));
+ if (TYPE_RANGE_DATA (TYPE_INDEX_TYPE (type))->high.kind
+ != RANGE_BOUND_KIND_CONSTANT)
+ {
+ /* No _() - printed sources should not be locale dependent. */
+ fprintf_filtered (stream, "variable");
+ }
+ else if (get_array_bounds (type, &low_bound, &high_bound))
+ fprintf_filtered (stream, "%d", (int) (high_bound - low_bound + 1));
fprintf_filtered (stream, "]");
c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream,
diff --git a/gdb/coffread.c b/gdb/coffread.c
index b11dd73..0868a79 100644
--- a/gdb/coffread.c
+++ b/gdb/coffread.c
@@ -2193,6 +2193,7 @@ static const struct sym_fns coff_sym_fns =
default_symfile_relocate, /* sym_relocate: Relocate a debug
section. */
+ NULL, /* sym_probe_fns */
&psym_functions
};
diff --git a/gdb/data-directory/Makefile.in b/gdb/data-directory/Makefile.in
index 11cf2e6..9a2a8f8 100644
--- a/gdb/data-directory/Makefile.in
+++ b/gdb/data-directory/Makefile.in
@@ -52,11 +52,23 @@ SYSCALLS_FILES = \
PYTHON_DIR = python
PYTHON_INSTALL_DIR = $(DESTDIR)$(GDB_DATADIR)/$(PYTHON_DIR)
PYTHON_FILES = \
+ gdb/FrameIterator.py \
+ gdb/FrameWrapper.py \
gdb/__init__.py \
- gdb/types.py \
- gdb/printing.py \
+ gdb/backtrace.py \
gdb/command/__init__.py \
- gdb/command/pretty_printers.py
+ gdb/command/alias.py \
+ gdb/command/backtrace.py \
+ gdb/command/ignore_errors.py \
+ gdb/command/pahole.py \
+ gdb/command/pretty_printers.py \
+ gdb/command/require.py \
+ gdb/command/upto.py \
+ gdb/function/__init__.py \
+ gdb/function/caller_is.py \
+ gdb/function/in_scope.py \
+ gdb/printing.py \
+ gdb/types.py
FLAGS_TO_PASS = \
"prefix=$(prefix)" \
diff --git a/gdb/dbxread.c b/gdb/dbxread.c
index 8242cf8..b2db699 100644
--- a/gdb/dbxread.c
+++ b/gdb/dbxread.c
@@ -1,6 +1,6 @@
/* Read dbx symbol tables and convert to internal format, for GDB.
Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
- 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2008, 2009, 2010.
+ 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2008, 2009, 2010, 2011.
Free Software Foundation, Inc.
This file is part of GDB.
@@ -3586,6 +3586,7 @@ static const struct sym_fns aout_sym_fns =
default_symfile_segments, /* Get segment information from a file. */
NULL,
default_symfile_relocate, /* Relocate a debug section. */
+ NULL, /* sym_probe_fns */
&psym_functions
};
diff --git a/gdb/defs.h b/gdb/defs.h
index 9409dde..f0fa4c7 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -398,6 +398,8 @@ extern struct cleanup *make_cleanup_restore_page_info (void);
extern struct cleanup *
set_batch_flag_and_make_cleanup_restore_page_info (void);
+extern struct cleanup *make_cleanup_restore_selected_frame (void);
+
extern char *gdb_realpath (const char *);
extern char *xfullpath (const char *);
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index fcbbd6c..876749d 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -1177,6 +1177,16 @@ for remote debugging.
Run using @var{device} for your program's standard input and output.
@c FIXME: kingdon thinks there is more to -tty. Investigate.
+@item -P
+@cindex @code{-P}
+@itemx --python
+@cindex @code{--python}
+Change interpretation of command line so that the argument immediately
+following this switch is taken to be the name of a Python script file.
+This option stops option processing; subsequent options are passed to
+Python as @code{sys.argv}. This option is only available if Python
+scripting support was enabled when @value{GDBN} was configured.
+
@c resolve the situation of these eventually
@item -tui
@cindex @code{--tui}
@@ -3286,6 +3296,7 @@ all breakpoints in that range are operated on.
* Conditions:: Break conditions
* Break Commands:: Breakpoint command lists
* Save Breakpoints:: How to save breakpoints in a file
+* Static Probe Points:: Listing static probe points
* Error in Breakpoints:: ``Cannot insert breakpoints''
* Breakpoint-related Warnings:: ``Breakpoint address adjusted...''
@end menu
@@ -4499,6 +4510,50 @@ and remove the breakpoint definitions you're not interested in, or
that can no longer be recreated.
@end table
+@node Static Probe Points
+@subsection Static Probe Points
+
+@cindex SystemTap static probe point
+@cindex sdt-probe
+The @sc{gnu}/Linux tool @code{SystemTap} provides a way for
+applications to embed static probes, using @file{sdt.h}. @value{GDBN}
+can list the available probes, and you can put breakpoints at the
+probe points (@pxref{Specify Location}).
+
+You can examine the available @code{SystemTap} static probes using
+@code{info probes}:
+
+@table @code
+@kindex info probes
+@item info probes [@var{provider} [@var{name} [@var{objfile}]]]
+List the available @code{SystemTap} static probes.
+
+If given, @var{provider} is a regular expression used to select which
+providers to list. If omitted, all providers are listed.
+
+If given, @var{name} is a regular expression used to select which
+probes to list. If omitted, all probes are listed.
+
+If given, @var{objfile} is a regular expression used to select which
+object files (executable or shared libraries) to examine. If not
+given, all object files are considered.
+@end table
+
+@vindex $_probe_arg@r{, convenience variable}
+A probe may specify up to ten arguments. These are available at the
+point at which the probe is defined---that is, when the current PC is
+at the probe's location. The arguments are available using the
+convenience variables (@pxref{Convenience Vars})
+@code{$_probe_arg0}@dots{}@code{$_probe_arg9}. Each probe argument is
+an integer of the appropriate size; types are not preserved. The
+convenience variable @code{$_probe_argc} holds the number of arguments
+at the current probe point.
+
+These variables are always available, but attempts to access them at
+any location other than a probe point will cause @value{GDBN} to give
+an error.
+
+
@c @ifclear BARETARGET
@node Error in Breakpoints
@subsection ``Cannot insert breakpoints''
@@ -6411,6 +6466,29 @@ specify the function unambiguously, e.g., if there are several
functions with identical names in different source files.
@end table
+@cindex SystemTap static probe point
+@item probe:@r{[}@var{objfile}:@r{]}@r{[}@var{provider}:@r{]}@var{name}
+The @sc{gnu}/Linux tool @code{SystemTap} provides a way for
+applications to embed static probes. This form of linespec specifies
+the location of such a static probe. See
+@uref{http://sourceware.org/systemtap/wiki/AddingUserSpaceProbingToApps}
+for more information on static probes.
+
+If @var{objfile} is given, only probes coming from that shared library
+or executable are considered. If @var{provider} is given, then only
+probes from that provider are considered.
+
+@xref{Static Probe Points}, for more information on finding and using
+static probes.
+
+Some probes have an associated semaphore variable; for instance, this
+happens automatically if you defined your probe using a DTrace-style
+@file{.d} file. If your probe has a semaphore, @value{GDBN} will
+automatically enable it when you specify a breakpoint using the
+@samp{probe:} notation. But, if you put a breakpoint at a probe's
+location by some other method (e.g., @code{break file:line}), then
+@value{GDBN} will not automatically set the semaphore.
+
@end table
@@ -8497,6 +8575,10 @@ to match the format in which the data was printed.
The variable @code{$_exitcode} is automatically set to the exit code when
the program being debugged terminates.
+@item $_probe_argc
+@itemx $_probe_arg0@dots{}$_probe_arg9
+Arguments to a SystemTap static probe. @xref{Static Probe Points}.
+
@item $_sdata
@vindex $_sdata@r{, inspect, convenience variable}
The variable @code{$_sdata} contains extra collected static tracepoint
@@ -20689,8 +20771,6 @@ containing @code{end}. For example:
@smallexample
(@value{GDBP}) python
-Type python script
-End with a line saying just "end".
>print 23
>end
23
@@ -20703,6 +20783,14 @@ in a Python script. This can be controlled using @code{maint set
python print-stack}: if @code{on}, the default, then Python stack
printing is enabled; if @code{off}, then Python stack printing is
disabled.
+
+@kindex maint set python auto-load
+@item maint set python auto-load
+By default, @value{GDBN} will attempt to automatically load Python
+code when an object file is opened. This can be controlled using
+@code{maint set python auto-load}: if @code{on}, the default, then
+Python auto-loading is enabled; if @code{off}, then Python
+auto-loading is disabled.
@end table
It is also possible to execute a Python script from the @value{GDBN}
@@ -20724,6 +20812,14 @@ and thus is always available.
@cindex python api
@cindex programming in python
+You can get quick online help for @value{GDBN}'s Python API by issuing
+the command @w{@kbd{python help (gdb)}}.
+
+Functions and methods which have two or more optional arguments allow
+them to be specified using keyword syntax. This allows passing some
+optional arguments while skipping others. Example:
+@w{@code{gdb.some_function ('foo', bar = 1, baz = 2)}}.
+
@cindex python stdout
@cindex python pagination
At startup, @value{GDBN} overrides Python's @code{sys.stdout} and
diff --git a/gdb/doc/gdbint.texinfo b/gdb/doc/gdbint.texinfo
index a494707..d5b9cf8 100644
--- a/gdb/doc/gdbint.texinfo
+++ b/gdb/doc/gdbint.texinfo
@@ -2104,6 +2104,18 @@ time, and so we attempt to handle symbols incrementally. For instance,
we create @dfn{partial symbol tables} consisting of only selected
symbols, and only expand them to full symbol tables when necessary.
+@menu
+* Symbol Reading::
+* Partial Symbol Tables::
+* Types::
+* Object File Formats::
+* Debugging File Formats::
+* Adding a New Symbol Reader to GDB::
+* Memory Management for Symbol Files::
+* Memory Management for Types::
+@end menu
+
+@node Symbol Reading
@section Symbol Reading
@cindex symbol reading
@@ -2196,6 +2208,7 @@ symtab. Upon return, @code{pst->readin} should have been set to 1, and
zero if there were no symbols in that part of the symbol file.
@end table
+@node Partial Symbol Tables
@section Partial Symbol Tables
@value{GDBN} has three types of symbol tables:
@@ -2297,6 +2310,7 @@ and partial symbol tables behind a set of function pointers known as
the @dfn{quick symbol functions}. These are documented in
@file{symfile.h}.
+@node Types
@section Types
@unnumberedsubsec Fundamental Types (e.g., @code{FT_VOID}, @code{FT_BOOLEAN}).
@@ -2319,6 +2333,7 @@ types map to one @code{TYPE_CODE_*} type, and are distinguished by
other members of the type struct, such as whether the type is signed
or unsigned, and how many bits it uses.
+@anchor{Builtin Types}
@unnumberedsubsec Builtin Types (e.g., @code{builtin_type_void}, @code{builtin_type_char}).
These are instances of type structs that roughly correspond to
@@ -2333,6 +2348,7 @@ only one instance exists, while @file{c-lang.c} builds as many
@code{TYPE_CODE_INT} types as needed, with each one associated with
some particular objfile.
+@node Object File Formats
@section Object File Formats
@cindex object file formats
@@ -2418,6 +2434,7 @@ SOM, which is a cross-language ABI).
The SOM reader is in @file{somread.c}.
+@node Debugging File Formats
@section Debugging File Formats
This section describes characteristics of debugging information that
@@ -2489,6 +2506,7 @@ DWARF 3 is an improved version of DWARF 2.
@cindex SOM debugging info
Like COFF, the SOM definition includes debugging information.
+@node Adding a New Symbol Reader to GDB
@section Adding a New Symbol Reader to @value{GDBN}
@cindex adding debugging info reader
@@ -2511,6 +2529,7 @@ will only ever be implemented by one object file format may be called
directly. This interface should be described in a file
@file{bfd/lib@var{xyz}.h}, which is included by @value{GDBN}.
+@node Memory Management for Symbol Files
@section Memory Management for Symbol Files
Most memory associated with a loaded symbol file is stored on
@@ -2522,10 +2541,45 @@ released when the objfile is unloaded or reloaded. Therefore one
objfile must not reference symbol or type data from another objfile;
they could be unloaded at different times.
-User convenience variables, et cetera, have associated types. Normally
-these types live in the associated objfile. However, when the objfile
-is unloaded, those types are deep copied to global memory, so that
-the values of the user variables and history items are not lost.
+@node Memory Management for Types
+@section Memory Management for Types
+@cindex memory management for types
+
+@findex TYPE_OBJFILE
+@code{TYPE_OBJFILE} macro indicates the current memory owner of the type.
+Non-@code{NULL} value indicates it is owned by an objfile (specifically by its
+obstack) and in such case the type remains valid till the objfile is unloaded
+or reloaded. For such types with an associated objfile no reference counting
+is being made.
+
+User convenience variables, et cetera, have associated types. Normally these
+types live in the associated objfile. However, when the objfile is unloaded,
+those types are deep copied to global memory, so that the values of the user
+variables and history items are not lost. During the copy they will get their
+@code{TYPE_OBJFILE} set to @code{NULL} and become so-called @dfn{reclaimable}
+types.
+
+Types with null @code{TYPE_OBJFILE} can be either permanent types
+(@pxref{Builtin Types}) or reclaimable types which will be deallocated at the
+first idle @value{GDBN} moment if the last object referencing them is removed.
+Permanent types are allocated by the function @code{alloc_type} (and its
+derivations like @code{init_type}) specifying objfile as @code{NULL}. The
+reclaimable types are created the same way but moreover they need to have
+@code{type_init_group} called to start their tracking as being possibly
+deallocatable.
+
+@findex free_all_types
+When @value{GDBN} gets idle it always calls the @code{free_all_types} function
+which deallocates any unused types. All types currently not owned by an
+objfile must be marked as used on each @code{free_all_types} call as they would
+get deallocated as unused otherwise.
+
+@code{free_all_types} automatically checks for any cross-type references such
+as through @code{TYPE_TARGET_TYPE}, @code{TYPE_POINTER_TYPE} etc.@: and
+prevents early deallocation for any such existing references. Reclaimable
+types may reference any other reclaimable types or even permanent types. But
+permanent types must not reference reclaimable types (nor an objfile associated
+type).
@node Language Support
diff --git a/gdb/doc/observer.texi b/gdb/doc/observer.texi
index d16c865..946ad95 100644
--- a/gdb/doc/observer.texi
+++ b/gdb/doc/observer.texi
@@ -223,6 +223,11 @@ Bytes from @var{data} to @var{data} + @var{len} have been written
to the current inferior at @var{addr}.
@end deftypefun
+@c @deftypefun void mark_used (void)
+@c Mark any possibly reclaimable objects as used during a mark-and-sweep garbage
+@c collector pass. Currently only @code{type_mark_used} marker is supported.
+@c @end deftypefun
+
@deftypefun void test_notification (int @var{somearg})
This observer is used for internal testing. Do not use.
See testsuite/gdb.gdb/observer.exp.
diff --git a/gdb/dwarf2expr.c b/gdb/dwarf2expr.c
index 8d1810e..4a3e2f2 100644
--- a/gdb/dwarf2expr.c
+++ b/gdb/dwarf2expr.c
@@ -905,6 +905,13 @@ execute_stack_op (struct dwarf_expr_context *ctx,
ctx->dwarf_call (ctx, result);
goto no_push;
+ case DW_OP_push_object_address:
+ if (ctx->get_object_address == NULL)
+ error (_("DWARF-2 expression error: DW_OP_push_object_address must "
+ "have a value to push."));
+ result = (ctx->get_object_address) (ctx->baton);
+ break;
+
default:
error (_("Unhandled dwarf expression opcode 0x%x"), op);
}
diff --git a/gdb/dwarf2expr.h b/gdb/dwarf2expr.h
index 78ff53f..c83f23d 100644
--- a/gdb/dwarf2expr.h
+++ b/gdb/dwarf2expr.h
@@ -114,9 +114,15 @@ struct dwarf_expr_context
#if 0
/* Not yet implemented. */
+ /* Return the location expression for the dwarf expression
+ subroutine in the die at OFFSET in the current compilation unit.
+ The result must be live until the current expression evaluation
+ is complete. */
+ unsigned char *(*get_subr) (void *baton, off_t offset, size_t *length);
+#endif
+
/* Return the `object address' for DW_OP_push_object_address. */
CORE_ADDR (*get_object_address) (void *baton);
-#endif
/* The current depth of dwarf expression recursion, via DW_OP_call*,
DW_OP_fbreg, DW_OP_push_object_address, etc., and the maximum
diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
index 9fd8df0..cbfb6d6 100644
--- a/gdb/dwarf2loc.c
+++ b/gdb/dwarf2loc.c
@@ -134,6 +134,9 @@ struct dwarf_expr_baton
{
struct frame_info *frame;
struct dwarf2_per_cu_data *per_cu;
+ /* From DW_TAG_variable's DW_AT_location (not DW_TAG_type's
+ DW_AT_data_location) for DW_OP_push_object_address. */
+ CORE_ADDR object_address;
};
/* Helper functions for dwarf2_evaluate_loc_desc. */
@@ -202,23 +205,33 @@ dwarf_expr_frame_base_1 (struct symbol *framefunc, CORE_ADDR pc,
symbaton = SYMBOL_LOCATION_BATON (framefunc);
*start = dwarf2_find_location_expression (symbaton, length, pc);
}
- else
+ else if (SYMBOL_COMPUTED_OPS (framefunc) == &dwarf2_locexpr_funcs)
{
struct dwarf2_locexpr_baton *symbaton;
symbaton = SYMBOL_LOCATION_BATON (framefunc);
- if (symbaton != NULL)
- {
- *length = symbaton->size;
- *start = symbaton->data;
- }
- else
- *start = NULL;
+ gdb_assert (symbaton != NULL);
+ *start = symbaton->data;
+ *length = symbaton->size;
+ }
+ else if (SYMBOL_COMPUTED_OPS (framefunc) == &dwarf2_missing_funcs)
+ {
+ struct dwarf2_locexpr_baton *symbaton;
+
+ symbaton = SYMBOL_LOCATION_BATON (framefunc);
+ gdb_assert (symbaton == NULL);
+ *start = NULL;
+ *length = 0; /* unused */
}
+ else
+ internal_error (__FILE__, __LINE__,
+ _("Unsupported SYMBOL_COMPUTED_OPS %p for \"%s\""),
+ SYMBOL_COMPUTED_OPS (framefunc),
+ SYMBOL_PRINT_NAME (framefunc));
if (*start == NULL)
error (_("Could not find the frame base for \"%s\"."),
- SYMBOL_NATURAL_NAME (framefunc));
+ SYMBOL_PRINT_NAME (framefunc));
}
/* Helper function for dwarf2_evaluate_loc_desc. Computes the CFA for
@@ -286,6 +299,172 @@ dwarf_expr_dwarf_call (struct dwarf_expr_context *ctx, size_t die_offset)
ctx->get_frame_pc, ctx->baton);
}
+static CORE_ADDR
+dwarf_expr_object_address (void *baton)
+{
+ struct dwarf_expr_baton *debaton = baton;
+
+ /* The message is suppressed in DWARF_BLOCK_EXEC. */
+ if (debaton->object_address == 0)
+ error (_("Cannot resolve DW_OP_push_object_address for a missing object"));
+
+ return debaton->object_address;
+}
+
+/* Address of the variable we are currently referring to. It is set from
+ DW_TAG_variable's DW_AT_location (not DW_TAG_type's DW_AT_data_location) for
+ DW_OP_push_object_address. */
+
+static CORE_ADDR object_address;
+
+/* Callers use object_address_set while their callers use the result set so we
+ cannot run the cleanup at the local block of our direct caller. Still we
+ should reset OBJECT_ADDRESS at least for the next GDB command. */
+
+static void
+object_address_cleanup (void *prev_save_voidp)
+{
+ CORE_ADDR *prev_save = prev_save_voidp;
+
+ object_address = *prev_save;
+ xfree (prev_save);
+}
+
+/* Set the base address - DW_AT_location - of a variable. It is being later
+ used to derive other object addresses by DW_OP_push_object_address.
+
+ It would be useful to sanity check ADDRESS - such as for some objects with
+ unset value_raw_address - but some valid addresses may be zero (such as first
+ objects in relocatable .o files). */
+
+void
+object_address_set (CORE_ADDR address)
+{
+ CORE_ADDR *prev_save;
+
+ prev_save = xmalloc (sizeof *prev_save);
+ *prev_save = object_address;
+ make_cleanup (object_address_cleanup, prev_save);
+
+ object_address = address;
+}
+
+/* Evaluate DWARF expression at DATA ... DATA + SIZE with its result readable
+ by dwarf_expr_fetch (RETVAL, 0). FRAME parameter can be NULL to call
+ get_selected_frame to find it. Returned dwarf_expr_context freeing is
+ pushed on the cleanup chain. */
+
+static struct dwarf_expr_context *
+dwarf_expr_prep_ctx (struct frame_info *frame, const gdb_byte *data,
+ size_t size, struct dwarf2_per_cu_data *per_cu)
+{
+ struct dwarf_expr_context *ctx;
+ struct dwarf_expr_baton baton;
+ struct objfile *objfile = dwarf2_per_cu_objfile (per_cu);
+ volatile struct gdb_exception ex;
+
+ baton.frame = frame;
+ baton.per_cu = per_cu;
+ baton.object_address = object_address;
+
+ ctx = new_dwarf_expr_context ();
+ make_cleanup_free_dwarf_expr_context (ctx);
+
+ ctx->gdbarch = get_objfile_arch (objfile);
+ ctx->addr_size = dwarf2_per_cu_addr_size (per_cu);
+ ctx->offset = dwarf2_per_cu_text_offset (per_cu);
+ ctx->baton = &baton;
+ ctx->read_reg = dwarf_expr_read_reg;
+ ctx->read_mem = dwarf_expr_read_mem;
+ ctx->get_frame_base = dwarf_expr_frame_base;
+ ctx->get_frame_cfa = dwarf_expr_frame_cfa;
+ ctx->get_frame_pc = dwarf_expr_frame_pc;
+ ctx->get_tls_address = dwarf_expr_tls_address;
+ ctx->dwarf_call = dwarf_expr_dwarf_call;
+ ctx->get_object_address = dwarf_expr_object_address;
+
+ TRY_CATCH (ex, RETURN_MASK_ERROR)
+ {
+ dwarf_expr_eval (ctx, data, size);
+ }
+ if (ex.reason < 0)
+ {
+ if (ex.error == NOT_AVAILABLE_ERROR)
+ return NULL;
+ else
+ throw_exception (ex);
+ }
+
+ /* It was used only during dwarf_expr_eval. */
+ ctx->baton = NULL;
+
+ return ctx;
+}
+
+/* Evaluate DWARF expression at DLBATON expecting it produces exactly one
+ CORE_ADDR result on the DWARF stack stack. */
+
+CORE_ADDR
+dwarf_locexpr_baton_eval (struct dwarf2_locexpr_baton *dlbaton)
+{
+ struct dwarf_expr_context *ctx;
+ CORE_ADDR retval;
+ struct cleanup *back_to = make_cleanup (null_cleanup, 0);
+
+ ctx = dwarf_expr_prep_ctx (get_selected_frame (NULL), dlbaton->data,
+ dlbaton->size, dlbaton->per_cu);
+ if (ctx == NULL)
+ throw_error (NOT_AVAILABLE_ERROR, _("Value not available"));
+ if (ctx->num_pieces > 0)
+ error (_("DW_OP_*piece is unsupported for DW_FORM_block"));
+
+ retval = dwarf_expr_fetch (ctx, 0);
+
+ if (ctx->location == DWARF_VALUE_REGISTER)
+ {
+ /* Inlined dwarf_expr_read_reg as we no longer have the baton. */
+
+ int gdb_regnum = gdbarch_dwarf2_reg_to_regnum (ctx->gdbarch, retval);
+ struct type *type = builtin_type (ctx->gdbarch)->builtin_data_ptr;
+ struct frame_info *frame = get_selected_frame (NULL);
+
+ retval = address_from_register (type, gdb_regnum, frame);
+ }
+
+ do_cleanups (back_to);
+
+ return retval;
+}
+
+/* Evaluate DWARF location list at DLLBATON expecting it produces exactly one
+ CORE_ADDR result stored to *ADDRP on the DWARF stack stack. If the result
+ could not be found return zero and keep *ADDRP unchanged. */
+
+int
+dwarf_loclist_baton_eval (struct dwarf2_loclist_baton *dllbaton,
+ struct type *type, CORE_ADDR *addrp)
+{
+ struct frame_info *frame = get_selected_frame (NULL);
+ const gdb_byte *data;
+ size_t size;
+ struct value *val;
+
+ if (!dllbaton)
+ return 0;
+
+ data = dwarf2_find_location_expression (dllbaton, &size,
+ get_frame_address_in_block (frame));
+ if (data == NULL)
+ return 0;
+
+ val = dwarf2_evaluate_loc_desc (type, frame, data, size, dllbaton->per_cu);
+ if (value_optimized_out (val))
+ return 0;
+
+ *addrp = value_as_address (val);
+ return 1;
+}
+
struct piece_closure
{
/* Reference count. */
@@ -1072,11 +1251,8 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
LONGEST byte_offset)
{
struct value *retval;
- struct dwarf_expr_baton baton;
struct dwarf_expr_context *ctx;
struct cleanup *old_chain;
- struct objfile *objfile = dwarf2_per_cu_objfile (per_cu);
- volatile struct gdb_exception ex;
if (byte_offset < 0)
invalid_synthetic_pointer ();
@@ -1089,38 +1265,14 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
return retval;
}
- baton.frame = frame;
- baton.per_cu = per_cu;
-
- ctx = new_dwarf_expr_context ();
- old_chain = make_cleanup_free_dwarf_expr_context (ctx);
-
- ctx->gdbarch = get_objfile_arch (objfile);
- ctx->addr_size = dwarf2_per_cu_addr_size (per_cu);
- ctx->offset = dwarf2_per_cu_text_offset (per_cu);
- ctx->baton = &baton;
- ctx->read_reg = dwarf_expr_read_reg;
- ctx->read_mem = dwarf_expr_read_mem;
- ctx->get_frame_base = dwarf_expr_frame_base;
- ctx->get_frame_cfa = dwarf_expr_frame_cfa;
- ctx->get_frame_pc = dwarf_expr_frame_pc;
- ctx->get_tls_address = dwarf_expr_tls_address;
- ctx->dwarf_call = dwarf_expr_dwarf_call;
+ old_chain = make_cleanup (null_cleanup, 0);
- TRY_CATCH (ex, RETURN_MASK_ERROR)
- {
- dwarf_expr_eval (ctx, data, size);
- }
- if (ex.reason < 0)
+ ctx = dwarf_expr_prep_ctx (frame, data, size, per_cu);
+ if (ctx == NULL)
{
- if (ex.error == NOT_AVAILABLE_ERROR)
- {
- retval = allocate_value (type);
- mark_value_bytes_unavailable (retval, 0, TYPE_LENGTH (type));
- return retval;
- }
- else
- throw_exception (ex);
+ retval = allocate_value (type);
+ mark_value_bytes_unavailable (retval, 0, TYPE_LENGTH (type));
+ return retval;
}
if (ctx->num_pieces > 0)
@@ -1166,6 +1318,15 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
CORE_ADDR address = dwarf_expr_fetch_address (ctx, 0);
int in_stack_memory = dwarf_expr_fetch_in_stack_memory (ctx, 0);
+ /* Frame may be needed for check_typedef of TYPE_DYNAMIC. */
+ make_cleanup_restore_selected_frame ();
+ select_frame (frame);
+
+ /* object_address_set called here is required in ALLOCATE_VALUE's
+ CHECK_TYPEDEF for the object's possible
+ DW_OP_push_object_address. */
+ object_address_set (address);
+
retval = allocate_value_lazy (type);
VALUE_LVAL (retval) = lval_memory;
if (in_stack_memory)
@@ -2850,11 +3011,51 @@ loclist_tracepoint_var_ref (struct symbol *symbol, struct gdbarch *gdbarch,
dlbaton->per_cu);
}
-/* The set of location functions used with the DWARF-2 expression
- evaluator and location lists. */
+/* The set of location functions used with the DWARF-2 location lists. */
const struct symbol_computed_ops dwarf2_loclist_funcs = {
loclist_read_variable,
loclist_read_needs_frame,
loclist_describe_location,
loclist_tracepoint_var_ref
};
+
+static struct value *
+missing_read_variable (struct symbol *symbol, struct frame_info *frame)
+{
+ struct dwarf2_loclist_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
+
+ gdb_assert (dlbaton == NULL);
+ error (_("Unable to resolve variable \"%s\""), SYMBOL_PRINT_NAME (symbol));
+}
+
+static int
+missing_read_needs_frame (struct symbol *symbol)
+{
+ return 0;
+}
+
+static void
+missing_describe_location (struct symbol *symbol, CORE_ADDR addr,
+ struct ui_file *stream)
+{
+ fprintf_filtered (stream, _("a variable we are unable to resolve"));
+}
+
+static void
+missing_tracepoint_var_ref (struct symbol *symbol, struct gdbarch *gdbarch,
+ struct agent_expr *ax, struct axs_value *value)
+{
+ struct dwarf2_loclist_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
+
+ gdb_assert (dlbaton == NULL);
+ error (_("Unable to resolve variable \"%s\""), SYMBOL_PRINT_NAME (symbol));
+}
+
+/* The set of location functions used with the DWARF-2 evaluator when we are
+ unable to resolve the symbols. */
+const struct symbol_computed_ops dwarf2_missing_funcs = {
+ missing_read_variable,
+ missing_read_needs_frame,
+ missing_describe_location,
+ missing_tracepoint_var_ref
+};
diff --git a/gdb/dwarf2loc.h b/gdb/dwarf2loc.h
index 96a490e..b0ebb06 100644
--- a/gdb/dwarf2loc.h
+++ b/gdb/dwarf2loc.h
@@ -107,6 +107,15 @@ struct dwarf2_loclist_baton
extern const struct symbol_computed_ops dwarf2_locexpr_funcs;
extern const struct symbol_computed_ops dwarf2_loclist_funcs;
+extern const struct symbol_computed_ops dwarf2_missing_funcs;
+
+extern void object_address_set (CORE_ADDR address);
+
+extern CORE_ADDR dwarf_locexpr_baton_eval
+ (struct dwarf2_locexpr_baton *dlbaton);
+
+extern int dwarf_loclist_baton_eval (struct dwarf2_loclist_baton *dllbaton,
+ struct type *type, CORE_ADDR *addrp);
/* Compile a DWARF location expression to an agent expression.
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 810f66a..f8d20ac 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -1211,6 +1211,9 @@ static void fill_in_loclist_baton (struct dwarf2_cu *cu,
struct dwarf2_loclist_baton *baton,
struct attribute *attr);
+static struct dwarf2_loclist_baton *dwarf2_attr_to_loclist_baton
+ (struct attribute *attr, struct dwarf2_cu *cu);
+
static void dwarf2_symbol_mark_computed (struct attribute *attr,
struct symbol *sym,
struct dwarf2_cu *cu);
@@ -1245,6 +1248,9 @@ static void age_cached_comp_units (void);
static void free_one_cached_comp_unit (void *);
+static void fetch_die_type_attrs (struct die_info *die, struct type *type,
+ struct dwarf2_cu *cu);
+
static struct type *set_die_type (struct die_info *, struct type *,
struct dwarf2_cu *);
@@ -1269,6 +1275,9 @@ static struct type *get_die_type_at_offset (unsigned int,
static struct type *get_die_type (struct die_info *die, struct dwarf2_cu *cu);
+static struct dwarf2_locexpr_baton *dwarf2_attr_to_locexpr_baton
+ (struct attribute *attr, struct dwarf2_cu *cu);
+
static void dwarf2_release_queue (void *dummy);
static void queue_comp_unit (struct dwarf2_per_cu_data *per_cu,
@@ -7315,6 +7324,29 @@ process_enumeration_scope (struct die_info *die, struct dwarf2_cu *cu)
new_symbol (die, this_type, cu);
}
+/* Create a new array dimension referencing its target type TYPE.
+
+ Multidimensional arrays are internally represented as a stack of
+ singledimensional arrays being referenced by their TYPE_TARGET_TYPE. */
+
+static struct type *
+create_single_array_dimension (struct type *type, struct type *range_type,
+ struct die_info *die, struct dwarf2_cu *cu)
+{
+ type = create_array_type (NULL, type, range_type);
+
+ /* These generic type attributes need to be fetched by
+ evaluate_subexp_standard <multi_f77_subscript>'s call of
+ value_subscripted_rvalue only for the innermost array type. */
+ fetch_die_type_attrs (die, type, cu);
+
+ /* These generic type attributes are checked for allocated/associated
+ validity while accessing FIELD_LOC_KIND_DWARF_BLOCK. */
+ fetch_die_type_attrs (die, range_type, cu);
+
+ return type;
+}
+
/* Extract all information from a DW_TAG_array_type DIE and put it in
the DIE's type field. For now, this only handles one dimensional
arrays. */
@@ -7328,7 +7360,7 @@ read_array_type (struct die_info *die, struct dwarf2_cu *cu)
struct type *element_type, *range_type, *index_type;
struct type **range_types = NULL;
struct attribute *attr;
- int ndim = 0;
+ int ndim = 0, i;
struct cleanup *back_to;
char *name;
@@ -7381,17 +7413,19 @@ read_array_type (struct die_info *die, struct dwarf2_cu *cu)
type = element_type;
if (read_array_order (die, cu) == DW_ORD_col_major)
- {
- int i = 0;
-
- while (i < ndim)
- type = create_array_type (NULL, type, range_types[i++]);
- }
- else
- {
- while (ndim-- > 0)
- type = create_array_type (NULL, type, range_types[ndim]);
- }
+ for (i = 0; i < ndim; i++)
+ type = create_single_array_dimension (type, range_types[i], die, cu);
+ else /* (read_array_order (die, cu) == DW_ORD_row_major) */
+ for (i = ndim - 1; i >= 0; i--)
+ type = create_single_array_dimension (type, range_types[i], die, cu);
+
+ /* Data locations should be set only for the outermost dimension as they
+ would be confusing for the dereferenced offset on the inner ones. */
+ attr = dwarf2_attr (die, DW_AT_data_location, cu);
+ if (attr_form_is_block (attr))
+ TYPE_DATA_LOCATION_DWARF_BLOCK (type)
+ = dwarf2_attr_to_locexpr_baton (attr, cu);
+ gdb_assert (!TYPE_DATA_LOCATION_IS_ADDR (type));
/* Understand Dwarf2 support for vector types (like they occur on
the PowerPC w/ AltiVec). Gcc just adds another attribute to the
@@ -7884,29 +7918,114 @@ read_tag_string_type (struct die_info *die, struct dwarf2_cu *cu)
struct gdbarch *gdbarch = get_objfile_arch (objfile);
struct type *type, *range_type, *index_type, *char_type;
struct attribute *attr;
- unsigned int length;
+ int length;
+
+ index_type = objfile_type (objfile)->builtin_int;
+ /* RANGE_TYPE is allocated from OBJFILE, not as a permanent type. */
+ range_type = alloc_type (objfile);
+ /* LOW_BOUND and HIGH_BOUND are set for real below. */
+ range_type = create_range_type (range_type, index_type, 0, -1);
+
+ /* C/C++ should probably have the low bound 0 but C/C++ does not use
+ DW_TAG_string_type. */
+ TYPE_LOW_BOUND (range_type) = 1;
attr = dwarf2_attr (die, DW_AT_string_length, cu);
- if (attr)
- {
- length = DW_UNSND (attr);
+ if (attr && attr_form_is_block (attr))
+ {
+ /* Security check for a size overflow. */
+ if (DW_BLOCK (attr)->size + 2 < DW_BLOCK (attr)->size)
+ TYPE_HIGH_BOUND (range_type) = 1;
+ /* Extend the DWARF block by a new DW_OP_deref/DW_OP_deref_size
+ instruction as DW_AT_string_length specifies the length location, not
+ its value. */
+ else
+ {
+ struct dwarf2_locexpr_baton *length_baton = NULL;
+ struct dwarf_block *blk = DW_BLOCK (attr);
+
+ /* Turn any single DW_OP_reg* into DW_OP_breg*(0) but clearing
+ DW_OP_deref* in such case. */
+
+ if (blk->size == 1 && blk->data[0] >= DW_OP_reg0
+ && blk->data[0] <= DW_OP_reg31)
+ length_baton = dwarf2_attr_to_locexpr_baton (attr, cu);
+ else if (blk->size > 1 && blk->data[0] == DW_OP_regx)
+ {
+ ULONGEST ulongest;
+ const gdb_byte *end;
+
+ end = read_uleb128 (&blk->data[1], &blk->data[blk->size],
+ &ulongest);
+ if (end == &blk->data[blk->size])
+ length_baton = dwarf2_attr_to_locexpr_baton (attr, cu);
+ }
+
+ if (length_baton == NULL)
+ {
+ struct attribute *size_attr;
+ gdb_byte *data;
+
+ length_baton = obstack_alloc (&cu->comp_unit_obstack,
+ sizeof (*length_baton));
+ length_baton->per_cu = cu->per_cu;
+ length_baton->size = DW_BLOCK (attr)->size + 2;
+ data = obstack_alloc (&cu->comp_unit_obstack,
+ length_baton->size);
+ length_baton->data = data;
+ memcpy (data, DW_BLOCK (attr)->data, DW_BLOCK (attr)->size);
+
+ /* DW_AT_BYTE_SIZE existing together with DW_AT_STRING_LENGTH
+ specifies the size of an integer to fetch. */
+ size_attr = dwarf2_attr (die, DW_AT_byte_size, cu);
+ if (size_attr)
+ {
+ data[DW_BLOCK (attr)->size] = DW_OP_deref_size;
+ data[DW_BLOCK (attr)->size + 1] = DW_UNSND (size_attr);
+ if (data[DW_BLOCK (attr)->size + 1] != DW_UNSND (size_attr))
+ complaint (&symfile_complaints,
+ _("DW_AT_string_length's DW_AT_byte_size "
+ "integer exceeds the byte size storage"));
+ }
+ else
+ {
+ data[DW_BLOCK (attr)->size] = DW_OP_deref;
+ data[DW_BLOCK (attr)->size + 1] = DW_OP_nop;
+ }
+ }
+
+ TYPE_RANGE_DATA (range_type)->high.kind
+ = RANGE_BOUND_KIND_DWARF_BLOCK;
+ TYPE_RANGE_DATA (range_type)->high.u.dwarf_block = length_baton;
+ TYPE_DYNAMIC (range_type) = 1;
+ }
}
else
{
- /* Check for the DW_AT_byte_size attribute. */
+ if (attr && attr_form_is_constant (attr))
+ {
+ /* We currently do not support a constant address where the location
+ should be read from - attr_form_is_block is expected instead. See
+ DWARF for the DW_AT_STRING_LENGTH vs. DW_AT_BYTE_SIZE difference.
+ */
+ /* PASSTHRU */
+ }
+
attr = dwarf2_attr (die, DW_AT_byte_size, cu);
- if (attr)
- {
- length = DW_UNSND (attr);
- }
+ if (attr && attr_form_is_block (attr))
+ {
+ TYPE_RANGE_DATA (range_type)->high.kind
+ = RANGE_BOUND_KIND_DWARF_BLOCK;
+ TYPE_RANGE_DATA (range_type)->high.u.dwarf_block =
+ dwarf2_attr_to_locexpr_baton (attr, cu);
+ TYPE_DYNAMIC (range_type) = 1;
+ }
+ else if (attr && attr_form_is_constant (attr))
+ TYPE_HIGH_BOUND (range_type) = dwarf2_get_attr_constant_value (attr, 0);
else
- {
- length = 1;
- }
+ TYPE_HIGH_BOUND (range_type) = 1;
}
- index_type = objfile_type (objfile)->builtin_int;
- range_type = create_range_type (NULL, index_type, 1, length);
char_type = language_string_char_type (cu->language_defn, gdbarch);
type = create_string_type (NULL, char_type, range_type);
@@ -8191,8 +8310,7 @@ read_subrange_type (struct die_info *die, struct dwarf2_cu *cu)
struct type *base_type;
struct type *range_type;
struct attribute *attr;
- LONGEST low = 0;
- LONGEST high = -1;
+ LONGEST low;
char *name;
LONGEST negative_mask;
@@ -8205,53 +8323,126 @@ read_subrange_type (struct die_info *die, struct dwarf2_cu *cu)
if (range_type)
return range_type;
- if (cu->language == language_fortran)
- {
- /* FORTRAN implies a lower bound of 1, if not given. */
- low = 1;
- }
+ /* LOW_BOUND and HIGH_BOUND are set for real below. */
+ range_type = create_range_type (NULL, base_type, 0, -1);
+ TYPE_UNSIGNED (range_type) = 0;
- /* FIXME: For variable sized arrays either of these could be
- a variable rather than a constant value. We'll allow it,
- but we don't know how to handle it. */
- attr = dwarf2_attr (die, DW_AT_lower_bound, cu);
- if (attr)
- low = dwarf2_get_attr_constant_value (attr, 0);
+ negative_mask =
+ (LONGEST) -1 << (TYPE_LENGTH (base_type) * TARGET_CHAR_BIT - 1);
- attr = dwarf2_attr (die, DW_AT_upper_bound, cu);
- if (attr)
+ /* Exclude language_ada from any TYPE_DYNAMIC constructs below. GDB Ada
+ supports implements the dynamic bounds in a non-DWARF way and the
+ existing DWARF dynamic bounds are invalid, leading to memory access
+ errors. */
+
+ attr = dwarf2_attr (die, DW_AT_lower_bound, cu);
+ if (attr && attr_form_is_block (attr) && cu->language != language_ada)
+ {
+ TYPE_RANGE_DATA (range_type)->low.kind = RANGE_BOUND_KIND_DWARF_BLOCK;
+ TYPE_RANGE_DATA (range_type)->low.u.dwarf_block =
+ dwarf2_attr_to_locexpr_baton (attr, cu);
+ TYPE_DYNAMIC (range_type) = 1;
+ /* For setting a default if DW_AT_UPPER_BOUND would be missing. */
+ low = 0;
+ }
+ else if (attr && is_ref_attr (attr) && cu->language != language_ada)
+ {
+ struct die_info *target_die;
+ struct dwarf2_cu *target_cu = cu;
+ struct attribute *target_loc_attr;
+
+ target_die = follow_die_ref_or_sig (die, attr, &target_cu);
+ gdb_assert (target_cu->objfile == cu->objfile);
+ target_loc_attr = dwarf2_attr (target_die, DW_AT_location, target_cu);
+
+ TYPE_RANGE_DATA (range_type)->low.kind = RANGE_BOUND_KIND_DWARF_LOCLIST;
+ TYPE_RANGE_DATA (range_type)->low.u.dwarf_loclist.loclist
+ = dwarf2_attr_to_loclist_baton (target_loc_attr, target_cu);
+ TYPE_RANGE_DATA (range_type)->low.u.dwarf_loclist.type
+ = die_type (target_die, target_cu);
+ TYPE_DYNAMIC (range_type) = 1;
+ /* For setting a default if DW_AT_UPPER_BOUND would be missing. */
+ low = 0;
+ }
+ else
{
- if (attr->form == DW_FORM_block1 || is_ref_attr (attr))
- {
- /* GCC encodes arrays with unspecified or dynamic length
- with a DW_FORM_block1 attribute or a reference attribute.
- FIXME: GDB does not yet know how to handle dynamic
- arrays properly, treat them as arrays with unspecified
- length for now.
-
- FIXME: jimb/2003-09-22: GDB does not really know
- how to handle arrays of unspecified length
- either; we just represent them as zero-length
- arrays. Choose an appropriate upper bound given
- the lower bound we've computed above. */
- high = low - 1;
- }
+ if (attr && attr_form_is_constant (attr))
+ low = dwarf2_get_attr_constant_value (attr, 0);
else
- high = dwarf2_get_attr_constant_value (attr, 1);
+ {
+ if (cu->language == language_fortran)
+ {
+ /* FORTRAN implies a lower bound of 1, if not given. */
+ low = 1;
+ }
+ else
+ {
+ /* According to DWARF we should assume the value 0 only for
+ LANGUAGE_C and LANGUAGE_CPLUS. */
+ low = 0;
+ }
+ }
+ if (!TYPE_UNSIGNED (base_type) && (low & negative_mask))
+ low |= negative_mask;
+ TYPE_LOW_BOUND (range_type) = low;
+ if (low >= 0)
+ TYPE_UNSIGNED (range_type) = 1;
}
- else
+
+ attr = dwarf2_attr (die, DW_AT_upper_bound, cu);
+ if (!attr || (!attr_form_is_block (attr) && !attr_form_is_constant (attr)
+ && !is_ref_attr (attr)))
{
attr = dwarf2_attr (die, DW_AT_count, cu);
- if (attr)
- {
- int count = dwarf2_get_attr_constant_value (attr, 1);
- high = low + count - 1;
+ /* It does not hurt but it is needlessly ineffective in check_typedef. */
+ if (attr && (attr_form_is_block (attr) || attr_form_is_constant (attr)))
+ {
+ TYPE_RANGE_HIGH_BOUND_IS_COUNT (range_type) = 1;
+ TYPE_DYNAMIC (range_type) = 1;
}
+ /* Pass it now as the regular DW_AT_upper_bound. */
+ }
+
+ if (attr && attr_form_is_block (attr) && cu->language != language_ada)
+ {
+ TYPE_RANGE_DATA (range_type)->high.kind = RANGE_BOUND_KIND_DWARF_BLOCK;
+ TYPE_RANGE_DATA (range_type)->high.u.dwarf_block =
+ dwarf2_attr_to_locexpr_baton (attr, cu);
+ TYPE_DYNAMIC (range_type) = 1;
+ }
+ else if (attr && is_ref_attr (attr) && cu->language != language_ada)
+ {
+ struct die_info *target_die;
+ struct dwarf2_cu *target_cu = cu;
+ struct attribute *target_loc_attr;
+
+ target_die = follow_die_ref_or_sig (die, attr, &target_cu);
+ gdb_assert (target_cu->objfile == cu->objfile);
+ target_loc_attr = dwarf2_attr (target_die, DW_AT_location, target_cu);
+
+ TYPE_RANGE_DATA (range_type)->high.kind = RANGE_BOUND_KIND_DWARF_LOCLIST;
+ TYPE_RANGE_DATA (range_type)->high.u.dwarf_loclist.loclist
+ = dwarf2_attr_to_loclist_baton (target_loc_attr, target_cu);
+ TYPE_RANGE_DATA (range_type)->high.u.dwarf_loclist.type
+ = die_type (target_die, target_cu);
+ TYPE_DYNAMIC (range_type) = 1;
+ }
+ else
+ {
+ LONGEST high;
+
+ if (attr && attr_form_is_constant (attr))
+ high = dwarf2_get_attr_constant_value (attr, 0);
else
{
- /* Unspecified array length. */
+ /* Ada expects an empty array on no boundary attributes. */
+ if (cu->language != language_ada)
+ TYPE_HIGH_BOUND_UNDEFINED (range_type) = 1;
high = low - 1;
}
+ if (!TYPE_UNSIGNED (base_type) && (high & negative_mask))
+ high |= negative_mask;
+ TYPE_HIGH_BOUND (range_type) = high;
}
/* Dwarf-2 specifications explicitly allows to create subrange types
@@ -8292,24 +8483,41 @@ read_subrange_type (struct die_info *die, struct dwarf2_cu *cu)
}
}
- negative_mask =
- (LONGEST) -1 << (TYPE_LENGTH (base_type) * TARGET_CHAR_BIT - 1);
- if (!TYPE_UNSIGNED (base_type) && (low & negative_mask))
- low |= negative_mask;
- if (!TYPE_UNSIGNED (base_type) && (high & negative_mask))
- high |= negative_mask;
-
- range_type = create_range_type (NULL, base_type, low, high);
+ /* DW_AT_bit_stride is currently unsupported as we count in bytes. */
+ attr = dwarf2_attr (die, DW_AT_byte_stride, cu);
+ if (attr && attr_form_is_block (attr) && cu->language != language_ada)
+ {
+ TYPE_RANGE_DATA (range_type)->byte_stride.kind
+ = RANGE_BOUND_KIND_DWARF_BLOCK;
+ TYPE_RANGE_DATA (range_type)->byte_stride.u.dwarf_block =
+ dwarf2_attr_to_locexpr_baton (attr, cu);
+ TYPE_DYNAMIC (range_type) = 1;
+ }
+ else if (attr && is_ref_attr (attr) && cu->language != language_ada)
+ {
+ struct die_info *target_die;
+ struct dwarf2_cu *target_cu = cu;
+ struct attribute *target_loc_attr;
- /* Mark arrays with dynamic length at least as an array of unspecified
- length. GDB could check the boundary but before it gets implemented at
- least allow accessing the array elements. */
- if (attr && attr->form == DW_FORM_block1)
- TYPE_HIGH_BOUND_UNDEFINED (range_type) = 1;
+ target_die = follow_die_ref_or_sig (die, attr, &target_cu);
+ gdb_assert (target_cu->objfile == cu->objfile);
+ target_loc_attr = dwarf2_attr (target_die, DW_AT_location, target_cu);
- /* Ada expects an empty array on no boundary attributes. */
- if (attr == NULL && cu->language != language_ada)
- TYPE_HIGH_BOUND_UNDEFINED (range_type) = 1;
+ TYPE_RANGE_DATA (range_type)->byte_stride.kind
+ = RANGE_BOUND_KIND_DWARF_LOCLIST;
+ TYPE_RANGE_DATA (range_type)->byte_stride.u.dwarf_loclist.loclist
+ = dwarf2_attr_to_loclist_baton (target_loc_attr, target_cu);
+ TYPE_RANGE_DATA (range_type)->byte_stride.u.dwarf_loclist.type
+ = die_type (target_die, target_cu);
+ TYPE_DYNAMIC (range_type) = 1;
+ }
+ else if (attr && attr_form_is_constant (attr))
+ {
+ TYPE_BYTE_STRIDE (range_type) = dwarf2_get_attr_constant_value (attr, 0);
+ if (TYPE_BYTE_STRIDE (range_type) == 0)
+ complaint (&symfile_complaints,
+ _("Found DW_AT_byte_stride with unsupported value 0"));
+ }
name = dwarf2_name (die, cu);
if (name)
@@ -10835,10 +11043,12 @@ var_decode_location (struct attribute *attr, struct symbol *sym,
(i.e. when the value of a register or memory location is
referenced, or a thread-local block, etc.). Then again, it might
not be worthwhile. I'm assuming that it isn't unless performance
- or memory numbers show me otherwise. */
+ or memory numbers show me otherwise.
+
+ SYMBOL_CLASS may get overriden by dwarf2_symbol_mark_computed. */
- dwarf2_symbol_mark_computed (attr, sym, cu);
SYMBOL_CLASS (sym) = LOC_COMPUTED;
+ dwarf2_symbol_mark_computed (attr, sym, cu);
}
/* Given a pointer to a DWARF information entry, figure out if we need
@@ -10876,6 +11086,8 @@ new_symbol_full (struct die_info *die, struct type *type, struct dwarf2_cu *cu,
else
sym = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct symbol);
OBJSTAT (objfile, n_syms++);
+ /* Some methods are called w/o checking SYMBOL_COMPUTED_OPS validity. */
+ SYMBOL_COMPUTED_OPS (sym) = &dwarf2_missing_funcs;
/* Cache this symbol's name and the name's demangled form (if any). */
SYMBOL_SET_LANGUAGE (sym, cu->language);
@@ -11648,6 +11860,9 @@ read_type_die_1 (struct die_info *die, struct dwarf2_cu *cu)
break;
}
+ if (this_type)
+ finalize_type (this_type);
+
return this_type;
}
@@ -14468,61 +14683,99 @@ fill_in_loclist_baton (struct dwarf2_cu *cu,
baton->base_address = cu->base_address;
}
-static void
-dwarf2_symbol_mark_computed (struct attribute *attr, struct symbol *sym,
- struct dwarf2_cu *cu)
+/* Convert DW_BLOCK into struct dwarf2_locexpr_baton. ATTR must be a DW_BLOCK
+ attribute type. */
+
+static struct dwarf2_locexpr_baton *
+dwarf2_attr_to_locexpr_baton (struct attribute *attr, struct dwarf2_cu *cu)
{
- if (attr_form_is_section_offset (attr)
- /* ".debug_loc" may not exist at all, or the offset may be outside
- the section. If so, fall through to the complaint in the
- other branch. */
- && DW_UNSND (attr) < dwarf2_section_size (dwarf2_per_objfile->objfile,
- &dwarf2_per_objfile->loc))
- {
- struct dwarf2_loclist_baton *baton;
+ struct dwarf2_locexpr_baton *baton;
- baton = obstack_alloc (&cu->objfile->objfile_obstack,
- sizeof (struct dwarf2_loclist_baton));
+ gdb_assert (attr_form_is_block (attr));
- fill_in_loclist_baton (cu, baton, attr);
+ baton = obstack_alloc (&cu->objfile->objfile_obstack, sizeof (*baton));
+ baton->per_cu = cu->per_cu;
+ gdb_assert (baton->per_cu);
- if (cu->base_known == 0)
- complaint (&symfile_complaints,
- _("Location list used without "
- "specifying the CU base address."));
+ /* Note that we're just copying the block's data pointer
+ here, not the actual data. We're still pointing into the
+ info_buffer for SYM's objfile; right now we never release
+ that buffer, but when we do clean up properly this may
+ need to change. */
+ baton->size = DW_BLOCK (attr)->size;
+ baton->data = DW_BLOCK (attr)->data;
+ gdb_assert (baton->size == 0 || baton->data != NULL);
+
+ return baton;
+}
+
+static struct dwarf2_loclist_baton *
+dwarf2_attr_to_loclist_baton (struct attribute *attr, struct dwarf2_cu *cu)
+{
+ struct dwarf2_loclist_baton *baton;
+
+ /* DW_AT_location of the referenced DIE may be missing if the referenced
+ variable has been optimized out. */
+ if (!attr)
+ return NULL;
+ dwarf2_read_section (dwarf2_per_objfile->objfile,
+ &dwarf2_per_objfile->loc);
+
+ if (!(attr_form_is_section_offset (attr)
+ /* ".debug_loc" may not exist at all, or the offset may be outside
+ the section. If so, fall through to the complaint in the
+ other branch. */
+ && DW_UNSND (attr) < dwarf2_section_size (dwarf2_per_objfile->objfile,
+ &dwarf2_per_objfile->loc)))
+ return NULL;
+
+ baton = obstack_alloc (&cu->objfile->objfile_obstack,
+ sizeof (struct dwarf2_loclist_baton));
+
+ fill_in_loclist_baton (cu, baton, attr);
+
+ if (cu->base_known == 0)
+ complaint (&symfile_complaints,
+ _("Location list used without "
+ "specifying the CU base address."));
+
+ return baton;
+}
+
+/* SYM may get its SYMBOL_CLASS overriden on invalid ATTR content. */
+
+static void
+dwarf2_symbol_mark_computed (struct attribute *attr, struct symbol *sym,
+ struct dwarf2_cu *cu)
+{
+ struct dwarf2_loclist_baton *loclist_baton;
+
+ loclist_baton = dwarf2_attr_to_loclist_baton (attr, cu);
+ if (loclist_baton)
+ {
SYMBOL_COMPUTED_OPS (sym) = &dwarf2_loclist_funcs;
- SYMBOL_LOCATION_BATON (sym) = baton;
+ SYMBOL_LOCATION_BATON (sym) = loclist_baton;
+ }
+ else if (attr_form_is_block (attr))
+ {
+ SYMBOL_COMPUTED_OPS (sym) = &dwarf2_locexpr_funcs;
+ SYMBOL_LOCATION_BATON (sym) = dwarf2_attr_to_locexpr_baton (attr, cu);
}
else
{
- struct dwarf2_locexpr_baton *baton;
+ dwarf2_invalid_attrib_class_complaint ("location description",
+ SYMBOL_NATURAL_NAME (sym));
- baton = obstack_alloc (&cu->objfile->objfile_obstack,
- sizeof (struct dwarf2_locexpr_baton));
- baton->per_cu = cu->per_cu;
- gdb_assert (baton->per_cu);
+ /* Some methods are called w/o checking SYMBOL_COMPUTED_OPS validity. */
- if (attr_form_is_block (attr))
- {
- /* Note that we're just copying the block's data pointer
- here, not the actual data. We're still pointing into the
- info_buffer for SYM's objfile; right now we never release
- that buffer, but when we do clean up properly this may
- need to change. */
- baton->size = DW_BLOCK (attr)->size;
- baton->data = DW_BLOCK (attr)->data;
- }
- else
- {
- dwarf2_invalid_attrib_class_complaint ("location description",
- SYMBOL_NATURAL_NAME (sym));
- baton->size = 0;
- baton->data = NULL;
- }
+ SYMBOL_COMPUTED_OPS (sym) = &dwarf2_missing_funcs;
+ SYMBOL_LOCATION_BATON (sym) = NULL;
- SYMBOL_COMPUTED_OPS (sym) = &dwarf2_locexpr_funcs;
- SYMBOL_LOCATION_BATON (sym) = baton;
+ /* For functions a missing DW_AT_frame_base does not optimize out the
+ whole function definition, only its frame base resolving. */
+ if (attr->name == DW_AT_location)
+ SYMBOL_CLASS (sym) = LOC_OPTIMIZED_OUT;
}
}
@@ -14868,6 +15121,25 @@ offset_and_type_eq (const void *item_lhs, const void *item_rhs)
return ofs_lhs->offset == ofs_rhs->offset;
}
+/* Fill in generic attributes applicable for type DIEs. */
+
+static void
+fetch_die_type_attrs (struct die_info *die, struct type *type,
+ struct dwarf2_cu *cu)
+{
+ struct attribute *attr;
+
+ attr = dwarf2_attr (die, DW_AT_allocated, cu);
+ if (attr_form_is_block (attr))
+ TYPE_ALLOCATED (type) = dwarf2_attr_to_locexpr_baton (attr, cu);
+ gdb_assert (!TYPE_NOT_ALLOCATED (type));
+
+ attr = dwarf2_attr (die, DW_AT_associated, cu);
+ if (attr_form_is_block (attr))
+ TYPE_ASSOCIATED (type) = dwarf2_attr_to_locexpr_baton (attr, cu);
+ gdb_assert (!TYPE_NOT_ASSOCIATED (type));
+}
+
/* Set the type associated with DIE to TYPE. Save it in CU's hash
table if necessary. For convenience, return TYPE.
@@ -14893,6 +15165,8 @@ set_die_type (struct die_info *die, struct type *type, struct dwarf2_cu *cu)
struct objfile *objfile = cu->objfile;
htab_t *type_hash_ptr;
+ fetch_die_type_attrs (die, type, cu);
+
/* For Ada types, make sure that the gnat-specific data is always
initialized (if not already set). There are a few types where
we should not be doing so, because the type-specific area is
diff --git a/gdb/elfread.c b/gdb/elfread.c
index e638a36..c1893fe 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -37,6 +37,14 @@
#include "complaints.h"
#include "demangle.h"
#include "psympriv.h"
+#include "gdbtypes.h"
+#include "value.h"
+#include "infcall.h"
+#include "gdbthread.h"
+#include "regcache.h"
+#include "stap-probe.h"
+#include "arch-utils.h"
+#include "gdbtypes.h"
extern void _initialize_elfread (void);
@@ -55,8 +63,30 @@ struct elfinfo
asection *mdebugsect; /* Section pointer for .mdebug section */
};
+/* Per-objfile data for Systemtap probe info. */
+
+static const struct objfile_data *stap_probe_key = NULL;
+
+/* Per-objfile data about Systemtap probes. */
+
+struct stap_probe_per_objfile
+ {
+ /* The number of probes in this objfile. */
+ int stap_num_probes;
+
+ /* The probes themselves. */
+ struct stap_probe *probes;
+ };
+
static void free_elfinfo (void *);
+/* Minimal symbols located at the GOT entries for .plt - that is the real
+ pointer where the given entry will jump to. It gets updated by the real
+ function address during lazy ld.so resolving in the inferior. These
+ minimal symbols are indexed for <tab>-completion. */
+
+#define SYMBOL_GOT_PLT_SUFFIX "@got.plt"
+
/* Locate the segments in ABFD. */
static struct symfile_segment_data *
@@ -184,7 +214,8 @@ record_minimal_symbol (const char *name, int name_len, int copy_name,
{
struct gdbarch *gdbarch = get_objfile_arch (objfile);
- if (ms_type == mst_text || ms_type == mst_file_text)
+ if (ms_type == mst_text || ms_type == mst_file_text
+ || ms_type == mst_text_gnu_ifunc)
address = gdbarch_smash_text_address (gdbarch, address);
return prim_record_minimal_symbol_full (name, name_len, copy_name, address,
@@ -393,7 +424,10 @@ elf_symtab_read (struct objfile *objfile, int type,
{
if (sym->flags & (BSF_GLOBAL | BSF_WEAK))
{
- ms_type = mst_text;
+ if (sym->flags & BSF_GNU_INDIRECT_FUNCTION)
+ ms_type = mst_text_gnu_ifunc;
+ else
+ ms_type = mst_text;
}
else if ((sym->name[0] == '.' && sym->name[1] == 'L')
|| ((sym->flags & BSF_LOCAL)
@@ -577,6 +611,467 @@ elf_symtab_read (struct objfile *objfile, int type,
do_cleanups (back_to);
}
+/* Build minimal symbols named `function@got.plt' (see SYMBOL_GOT_PLT_SUFFIX)
+ for later look ups of which function to call when user requests
+ a STT_GNU_IFUNC function. As the STT_GNU_IFUNC type is found at the target
+ library defining `function' we cannot yet know while reading OBJFILE which
+ of the SYMBOL_GOT_PLT_SUFFIX entries will be needed and later
+ DYN_SYMBOL_TABLE is no longer easily available for OBJFILE. */
+
+static void
+elf_rel_plt_read (struct objfile *objfile, asymbol **dyn_symbol_table)
+{
+ bfd *obfd = objfile->obfd;
+ const struct elf_backend_data *bed = get_elf_backend_data (obfd);
+ asection *plt, *relplt, *got_plt;
+ unsigned u;
+ int plt_elf_idx;
+ bfd_size_type reloc_count, reloc;
+ char *string_buffer = NULL;
+ size_t string_buffer_size = 0;
+ struct cleanup *back_to;
+ struct gdbarch *gdbarch = objfile->gdbarch;
+ struct type *ptr_type = builtin_type (gdbarch)->builtin_data_ptr;
+ size_t ptr_size = TYPE_LENGTH (ptr_type);
+
+ if (objfile->separate_debug_objfile_backlink)
+ return;
+
+ plt = bfd_get_section_by_name (obfd, ".plt");
+ if (plt == NULL)
+ return;
+ plt_elf_idx = elf_section_data (plt)->this_idx;
+
+ got_plt = bfd_get_section_by_name (obfd, ".got.plt");
+ if (got_plt == NULL)
+ return;
+
+ /* This search algorithm is from _bfd_elf_canonicalize_dynamic_reloc. */
+ for (relplt = obfd->sections; relplt != NULL; relplt = relplt->next)
+ if (elf_section_data (relplt)->this_hdr.sh_info == plt_elf_idx
+ && (elf_section_data (relplt)->this_hdr.sh_type == SHT_REL
+ || elf_section_data (relplt)->this_hdr.sh_type == SHT_RELA))
+ break;
+ if (relplt == NULL)
+ return;
+
+ if (! bed->s->slurp_reloc_table (obfd, relplt, dyn_symbol_table, TRUE))
+ return;
+
+ back_to = make_cleanup (free_current_contents, &string_buffer);
+
+ reloc_count = relplt->size / elf_section_data (relplt)->this_hdr.sh_entsize;
+ for (reloc = 0; reloc < reloc_count; reloc++)
+ {
+ const char *name, *name_got_plt;
+ struct minimal_symbol *msym;
+ CORE_ADDR address;
+ const size_t got_suffix_len = strlen (SYMBOL_GOT_PLT_SUFFIX);
+ size_t name_len;
+
+ name = bfd_asymbol_name (*relplt->relocation[reloc].sym_ptr_ptr);
+ name_len = strlen (name);
+ address = relplt->relocation[reloc].address;
+
+ /* Does the pointer reside in the .got.plt section? */
+ if (!(bfd_get_section_vma (obfd, got_plt) <= address
+ && address < bfd_get_section_vma (obfd, got_plt)
+ + bfd_get_section_size (got_plt)))
+ continue;
+
+ /* We cannot check if NAME is a reference to mst_text_gnu_ifunc as in
+ OBJFILE the symbol is undefined and the objfile having NAME defined
+ may not yet have been loaded. */
+
+ if (string_buffer_size < name_len + got_suffix_len)
+ {
+ string_buffer_size = 2 * (name_len + got_suffix_len);
+ string_buffer = xrealloc (string_buffer, string_buffer_size);
+ }
+ memcpy (string_buffer, name, name_len);
+ memcpy (&string_buffer[name_len], SYMBOL_GOT_PLT_SUFFIX,
+ got_suffix_len);
+
+ msym = record_minimal_symbol (string_buffer, name_len + got_suffix_len,
+ 1, address, mst_slot_got_plt, got_plt,
+ objfile);
+ if (msym)
+ MSYMBOL_SIZE (msym) = ptr_size;
+ }
+
+ do_cleanups (back_to);
+}
+
+/* The data pointer is htab_t for gnu_ifunc_record_cache_unchecked. */
+
+static const struct objfile_data *elf_objfile_gnu_ifunc_cache_data;
+
+/* Map function names to CORE_ADDR in elf_objfile_gnu_ifunc_cache_data. */
+
+struct elf_gnu_ifunc_cache
+{
+ /* This is always a function entry address, not a function descriptor. */
+ CORE_ADDR addr;
+
+ char name[1];
+};
+
+/* htab_hash for elf_objfile_gnu_ifunc_cache_data. */
+
+static hashval_t
+elf_gnu_ifunc_cache_hash (const void *a_voidp)
+{
+ const struct elf_gnu_ifunc_cache *a = a_voidp;
+
+ return htab_hash_string (a->name);
+}
+
+/* htab_eq for elf_objfile_gnu_ifunc_cache_data. */
+
+static int
+elf_gnu_ifunc_cache_eq (const void *a_voidp, const void *b_voidp)
+{
+ const struct elf_gnu_ifunc_cache *a = a_voidp;
+ const struct elf_gnu_ifunc_cache *b = b_voidp;
+
+ return strcmp (a->name, b->name) == 0;
+}
+
+/* Record the target function address of a STT_GNU_IFUNC function NAME is the
+ function entry address ADDR. Return 1 if NAME and ADDR are considered as
+ valid and therefore they were successfully recorded, return 0 otherwise.
+
+ Function does not expect a duplicate entry. Use
+ elf_gnu_ifunc_resolve_by_cache first to check if the entry for NAME already
+ exists. */
+
+static int
+elf_gnu_ifunc_record_cache (const char *name, CORE_ADDR addr)
+{
+ struct minimal_symbol *msym;
+ asection *sect;
+ struct objfile *objfile;
+ htab_t htab;
+ struct elf_gnu_ifunc_cache entry_local, *entry_p;
+ void **slot;
+
+ msym = lookup_minimal_symbol_by_pc (addr);
+ if (msym == NULL)
+ return 0;
+ if (SYMBOL_VALUE_ADDRESS (msym) != addr)
+ return 0;
+ /* minimal symbols have always SYMBOL_OBJ_SECTION non-NULL. */
+ sect = SYMBOL_OBJ_SECTION (msym)->the_bfd_section;
+ objfile = SYMBOL_OBJ_SECTION (msym)->objfile;
+
+ /* If .plt jumps back to .plt the symbol is still deferred for later
+ resolution and it has no use for GDB. Besides ".text" this symbol can
+ reside also in ".opd" for ppc64 function descriptor. */
+ if (strcmp (bfd_get_section_name (objfile->obfd, sect), ".plt") == 0)
+ return 0;
+
+ htab = objfile_data (objfile, elf_objfile_gnu_ifunc_cache_data);
+ if (htab == NULL)
+ {
+ htab = htab_create_alloc_ex (1, elf_gnu_ifunc_cache_hash,
+ elf_gnu_ifunc_cache_eq,
+ NULL, &objfile->objfile_obstack,
+ hashtab_obstack_allocate,
+ dummy_obstack_deallocate);
+ set_objfile_data (objfile, elf_objfile_gnu_ifunc_cache_data, htab);
+ }
+
+ entry_local.addr = addr;
+ obstack_grow (&objfile->objfile_obstack, &entry_local,
+ offsetof (struct elf_gnu_ifunc_cache, name));
+ obstack_grow_str0 (&objfile->objfile_obstack, name);
+ entry_p = obstack_finish (&objfile->objfile_obstack);
+
+ slot = htab_find_slot (htab, entry_p, INSERT);
+ if (*slot != NULL)
+ {
+ struct elf_gnu_ifunc_cache *entry_found_p = *slot;
+ struct gdbarch *gdbarch = objfile->gdbarch;
+
+ if (entry_found_p->addr != addr)
+ {
+ /* This case indicates buggy inferior program, the resolved address
+ should never change. */
+
+ warning (_("gnu-indirect-function \"%s\" has changed its resolved "
+ "function_address from %s to %s"),
+ name, paddress (gdbarch, entry_found_p->addr),
+ paddress (gdbarch, addr));
+ }
+
+ /* New ENTRY_P is here leaked/duplicate in the OBJFILE obstack. */
+ }
+ *slot = entry_p;
+
+ return 1;
+}
+
+/* Try to find the target resolved function entry address of a STT_GNU_IFUNC
+ function NAME. If the address is found it is stored to *ADDR_P (if ADDR_P
+ is not NULL) and the function returns 1. It returns 0 otherwise.
+
+ Only the elf_objfile_gnu_ifunc_cache_data hash table is searched by this
+ function. */
+
+static int
+elf_gnu_ifunc_resolve_by_cache (const char *name, CORE_ADDR *addr_p)
+{
+ struct objfile *objfile;
+
+ ALL_PSPACE_OBJFILES (current_program_space, objfile)
+ {
+ htab_t htab;
+ struct elf_gnu_ifunc_cache *entry_p;
+ void **slot;
+
+ htab = objfile_data (objfile, elf_objfile_gnu_ifunc_cache_data);
+ if (htab == NULL)
+ continue;
+
+ entry_p = alloca (sizeof (*entry_p) + strlen (name));
+ strcpy (entry_p->name, name);
+
+ slot = htab_find_slot (htab, entry_p, NO_INSERT);
+ if (slot == NULL)
+ continue;
+ entry_p = *slot;
+ gdb_assert (entry_p != NULL);
+
+ if (addr_p)
+ *addr_p = entry_p->addr;
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Try to find the target resolved function entry address of a STT_GNU_IFUNC
+ function NAME. If the address is found it is stored to *ADDR_P (if ADDR_P
+ is not NULL) and the function returns 1. It returns 0 otherwise.
+
+ Only the SYMBOL_GOT_PLT_SUFFIX locations are searched by this function.
+ elf_gnu_ifunc_resolve_by_cache must have been already called for NAME to
+ prevent cache entries duplicates. */
+
+static int
+elf_gnu_ifunc_resolve_by_got (const char *name, CORE_ADDR *addr_p)
+{
+ char *name_got_plt;
+ struct objfile *objfile;
+ const size_t got_suffix_len = strlen (SYMBOL_GOT_PLT_SUFFIX);
+
+ name_got_plt = alloca (strlen (name) + got_suffix_len + 1);
+ sprintf (name_got_plt, "%s" SYMBOL_GOT_PLT_SUFFIX, name);
+
+ ALL_PSPACE_OBJFILES (current_program_space, objfile)
+ {
+ bfd *obfd = objfile->obfd;
+ struct gdbarch *gdbarch = objfile->gdbarch;
+ struct type *ptr_type = builtin_type (gdbarch)->builtin_data_ptr;
+ size_t ptr_size = TYPE_LENGTH (ptr_type);
+ CORE_ADDR pointer_address, addr;
+ asection *plt;
+ gdb_byte *buf = alloca (ptr_size);
+ struct minimal_symbol *msym;
+
+ msym = lookup_minimal_symbol (name_got_plt, NULL, objfile);
+ if (msym == NULL)
+ continue;
+ if (MSYMBOL_TYPE (msym) != mst_slot_got_plt)
+ continue;
+ pointer_address = SYMBOL_VALUE_ADDRESS (msym);
+
+ plt = bfd_get_section_by_name (obfd, ".plt");
+ if (plt == NULL)
+ continue;
+
+ if (MSYMBOL_SIZE (msym) != ptr_size)
+ continue;
+ if (target_read_memory (pointer_address, buf, ptr_size) != 0)
+ continue;
+ addr = extract_typed_address (buf, ptr_type);
+ addr = gdbarch_convert_from_func_ptr_addr (gdbarch, addr,
+ &current_target);
+
+ if (addr_p)
+ *addr_p = addr;
+ if (elf_gnu_ifunc_record_cache (name, addr))
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Try to find the target resolved function entry address of a STT_GNU_IFUNC
+ function NAME. If the address is found it is stored to *ADDR_P (if ADDR_P
+ is not NULL) and the function returns 1. It returns 0 otherwise.
+
+ Both the elf_objfile_gnu_ifunc_cache_data hash table and
+ SYMBOL_GOT_PLT_SUFFIX locations are searched by this function. */
+
+static int
+elf_gnu_ifunc_resolve_name (const char *name, CORE_ADDR *addr_p)
+{
+ if (elf_gnu_ifunc_resolve_by_cache (name, addr_p))
+ return 1;
+
+ if (elf_gnu_ifunc_resolve_by_got (name, addr_p))
+ return 1;
+
+ return 0;
+}
+
+/* Call STT_GNU_IFUNC - a function returning addresss of a real function to
+ call. PC is theSTT_GNU_IFUNC resolving function entry. The value returned
+ is the entry point of the resolved STT_GNU_IFUNC target function to call.
+ */
+
+static CORE_ADDR
+elf_gnu_ifunc_resolve_addr (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ char *name_at_pc;
+ CORE_ADDR start_at_pc, address;
+ struct type *func_func_type = builtin_type (gdbarch)->builtin_func_func;
+ struct value *function, *address_val;
+
+ /* Try first any non-intrusive methods without an inferior call. */
+
+ if (find_pc_partial_function (pc, &name_at_pc, &start_at_pc, NULL)
+ && start_at_pc == pc)
+ {
+ if (elf_gnu_ifunc_resolve_name (name_at_pc, &address))
+ return address;
+ }
+ else
+ name_at_pc = NULL;
+
+ function = allocate_value (func_func_type);
+ set_value_address (function, pc);
+
+ /* STT_GNU_IFUNC resolver functions have no parameters. FUNCTION is the
+ function entry address. ADDRESS may be a function descriptor. */
+
+ address_val = call_function_by_hand (function, 0, NULL);
+ address = value_as_address (address_val);
+ address = gdbarch_convert_from_func_ptr_addr (gdbarch, address,
+ &current_target);
+
+ if (name_at_pc)
+ elf_gnu_ifunc_record_cache (name_at_pc, address);
+
+ return address;
+}
+
+/* Handle inferior hit of bp_gnu_ifunc_resolver, see its definition. */
+
+static void
+elf_gnu_ifunc_resolver_stop (struct breakpoint *b)
+{
+ struct breakpoint *b_return;
+ struct frame_info *prev_frame = get_prev_frame (get_current_frame ());
+ struct frame_id prev_frame_id = get_stack_frame_id (prev_frame);
+ CORE_ADDR prev_pc = get_frame_pc (prev_frame);
+ int thread_id = pid_to_thread_id (inferior_ptid);
+
+ gdb_assert (b->type == bp_gnu_ifunc_resolver);
+
+ for (b_return = b->related_breakpoint; b_return != b;
+ b_return = b_return->related_breakpoint)
+ {
+ gdb_assert (b_return->type == bp_gnu_ifunc_resolver_return);
+ gdb_assert (b_return->loc != NULL && b_return->loc->next == NULL);
+ gdb_assert (frame_id_p (b_return->frame_id));
+
+ if (b_return->thread == thread_id
+ && b_return->loc->requested_address == prev_pc
+ && frame_id_eq (b_return->frame_id, prev_frame_id))
+ break;
+ }
+
+ if (b_return == b)
+ {
+ struct symtab_and_line sal;
+
+ /* No need to call find_pc_line for symbols resolving as this is only
+ a helper breakpointer never shown to the user. */
+
+ init_sal (&sal);
+ sal.pspace = current_inferior ()->pspace;
+ sal.pc = prev_pc;
+ sal.section = find_pc_overlay (sal.pc);
+ sal.explicit_pc = 1;
+ b_return = set_momentary_breakpoint (get_frame_arch (prev_frame), sal,
+ prev_frame_id,
+ bp_gnu_ifunc_resolver_return);
+
+ /* Add new b_return to the ring list b->related_breakpoint. */
+ gdb_assert (b_return->related_breakpoint == b_return);
+ b_return->related_breakpoint = b->related_breakpoint;
+ b->related_breakpoint = b_return;
+ }
+}
+
+/* Handle inferior hit of bp_gnu_ifunc_resolver_return, see its definition. */
+
+static void
+elf_gnu_ifunc_resolver_return_stop (struct breakpoint *b)
+{
+ struct gdbarch *gdbarch = get_frame_arch (get_current_frame ());
+ struct type *func_func_type = builtin_type (gdbarch)->builtin_func_func;
+ struct type *value_type = TYPE_TARGET_TYPE (func_func_type);
+ struct regcache *regcache = get_thread_regcache (inferior_ptid);
+ struct value *value;
+ CORE_ADDR resolved_address, resolved_pc;
+ struct symtab_and_line sal;
+ struct symtabs_and_lines sals;
+
+ gdb_assert (b->type == bp_gnu_ifunc_resolver_return);
+
+ value = allocate_value (value_type);
+ gdbarch_return_value (gdbarch, func_func_type, value_type, regcache,
+ value_contents_raw (value), NULL);
+ resolved_address = value_as_address (value);
+ resolved_pc = gdbarch_convert_from_func_ptr_addr (gdbarch,
+ resolved_address,
+ &current_target);
+
+ while (b->related_breakpoint != b)
+ {
+ struct breakpoint *b_next = b->related_breakpoint;
+
+ switch (b->type)
+ {
+ case bp_gnu_ifunc_resolver:
+ break;
+ case bp_gnu_ifunc_resolver_return:
+ delete_breakpoint (b);
+ break;
+ default:
+ internal_error (__FILE__, __LINE__,
+ _("handle_inferior_event: Invalid "
+ "gnu-indirect-function breakpoint type %d"),
+ (int) b->type);
+ }
+ b = b_next;
+ }
+ gdb_assert (b->type == bp_gnu_ifunc_resolver);
+
+ gdb_assert (current_program_space == b->pspace);
+ elf_gnu_ifunc_record_cache (b->addr_string, resolved_pc);
+
+ sal = find_pc_line (resolved_pc, 0);
+ sals.nelts = 1;
+ sals.sals = &sal;
+
+ b->type = bp_breakpoint;
+ update_breakpoint_locations (b, sals);
+}
+
struct build_id
{
size_t size;
@@ -817,6 +1312,8 @@ elf_symfile_read (struct objfile *objfile, int symfile_flags)
bfd_errmsg (bfd_get_error ()));
elf_symtab_read (objfile, ST_DYNAMIC, dynsymcount, dyn_symbol_table, 0);
+
+ elf_rel_plt_read (objfile, dyn_symbol_table);
}
/* Add synthetic symbols - for instance, names for any PLT entries. */
@@ -1071,7 +1568,243 @@ elfstab_offset_sections (struct objfile *objfile, struct partial_symtab *pst)
complaint (&symfile_complaints,
_("elf/stab section information missing for %s"), filename);
}
+
+/* Helper function that parses the information contained in a
+ Systemtap's probe. Basically, the information consists in:
+
+ - Probe's PC address;
+ - Link-time section address of `.stapsdt.base' section;
+ - Link-time address of the semaphore variable, or ZERO if the
+ probe doesn't have an associated semaphore;
+ - Probe's provider name;
+ - Probe's name;
+ - Probe's argument format. */
+
+static void
+handle_probe (struct objfile *objfile, struct sdt_note *el,
+ struct stap_probe *ret, CORE_ADDR base)
+{
+ bfd *abfd = objfile->obfd;
+ int size = bfd_get_arch_size (abfd) / 8;
+ struct gdbarch *gdbarch = get_objfile_arch (objfile);
+ struct type *ptr_type = builtin_type (gdbarch)->builtin_data_ptr;
+ CORE_ADDR base_ref;
+
+ /* Provider and the name of the probe. */
+ ret->provider = (const char *) &el->data[3 * size];
+ ret->name = memchr (ret->provider, '\0',
+ (unsigned long *) el->data
+ + el->size - (unsigned long *) ret->provider);
+ /* Making sure there is a name. */
+ if (!ret->name)
+ complaint (&symfile_complaints, _("corrupt probe when reading `%s'"),
+ objfile->name);
+ else
+ ++ret->name;
+
+ /* Retrieving the probe's address. */
+ ret->address = extract_typed_address ((const gdb_byte *) &el->data[0],
+ ptr_type);
+ /* Link-time sh_addr of `.stapsdt.base' section. */
+ base_ref = extract_typed_address ((const gdb_byte *) &el->data[size],
+ ptr_type);
+ /* Semaphore address. */
+ ret->sem_addr = extract_typed_address ((const gdb_byte *) &el->data[2 * size],
+ ptr_type);
+
+ ret->address += (ANOFFSET (objfile->section_offsets,
+ SECT_OFF_TEXT (objfile))
+ + base - base_ref);
+ if (ret->sem_addr)
+ ret->sem_addr += (ANOFFSET (objfile->section_offsets,
+ SECT_OFF_DATA (objfile))
+ + base - base_ref);
+
+ /* Arguments. We can only extract the argument format if there is a valid
+ name for this probe. */
+ if (ret->name)
+ {
+ ret->args = memchr (ret->name, '\0',
+ (unsigned long *) el->data
+ + el->size - (unsigned long *) ret->name);
+
+ if (ret->args++ != NULL
+ || memchr (ret->args, '\0', (unsigned long *) el->data
+ + el->size - (unsigned long *) ret->name)
+ != el->data + el->size - 1)
+ complaint (&symfile_complaints, _("corrupt probe when reading `%s'"),
+ objfile->name);
+ }
+ else
+ ret->args = NULL;
+}
+
+#define STAP_BASE_SECTION_NAME ".stapsdt.base"
+
+static void
+get_base_address_1 (bfd *abfd, asection *sect, void *obj)
+{
+ bfd_vma *base = (bfd_vma *) obj;
+
+ if (*base == (bfd_vma) -1
+ && (sect->flags & (SEC_DATA | SEC_ALLOC | SEC_HAS_CONTENTS))
+ && sect->name && !strcmp (sect->name, STAP_BASE_SECTION_NAME))
+ *base = sect->vma;
+}
+
+static bfd_vma
+get_base_address (bfd *obfd)
+{
+ bfd_vma base = (bfd_vma) -1;
+
+ bfd_map_over_sections (obfd, get_base_address_1, (void *) &base);
+
+ return base;
+}
+
+/* FIXME JUST FOR TESTING **/
+static int
+elf_get_probe_argument_count (struct objfile *objfile,
+ const struct stap_probe *probe);
+
+static const struct stap_probe *
+elf_get_probes (struct objfile *objfile, int *num_probes)
+{
+ struct stap_probe *ret = NULL;
+ struct stap_probe_per_objfile *probes_per_objfile;
+
+ /* Initially, no probes. */
+ *num_probes = 0;
+
+ /* Have we parsed this objfile's probes already? */
+ probes_per_objfile
+ = (struct stap_probe_per_objfile *) objfile_data (objfile,
+ stap_probe_key);
+
+ if (!probes_per_objfile)
+ {
+ /* If we are here, then this is the first time we are parsing the
+ probe's information. We basically have to count how many probes
+ the objfile has, and then fill in the necessary information
+ for each one. */
+
+ bfd *obfd = objfile->obfd;
+ bfd_vma base = get_base_address (obfd);
+ struct sdt_note *iter;
+ int i;
+ int n = 0;
+
+ if (! elf_tdata (obfd)->sdt_note_head)
+ /* There isn't any probe here. */
+ return NULL;
+
+ /* Allocating space for probe info. */
+ for (iter = elf_tdata (obfd)->sdt_note_head;
+ iter;
+ iter = iter->next, ++n);
+
+ ret = xcalloc (n, sizeof (struct stap_probe));
+
+ /* Parsing each probe's information. */
+ for (iter = elf_tdata (obfd)->sdt_note_head, i = 0;
+ iter;
+ iter = iter->next, i++)
+ /* We first have to handle all the information about the
+ probe which is present in the section. */
+ handle_probe (objfile, iter, &ret[i], base);
+
+ /* Creating a cache for these probes in the objfile's registry. */
+ probes_per_objfile = xmalloc (sizeof (struct stap_probe_per_objfile));
+
+ probes_per_objfile->stap_num_probes = n;
+ probes_per_objfile->probes = ret;
+
+ set_objfile_data (objfile, stap_probe_key, probes_per_objfile);
+ }
+ else
+ ret = probes_per_objfile->probes;
+
+ *num_probes = probes_per_objfile->stap_num_probes;
+
+ return ret;
+}
+
+static int
+elf_get_probe_argument_count (struct objfile *objfile,
+ const struct stap_probe *probe)
+{
+ const char *pargs = probe->args;
+
+ if (!pargs || !*pargs || *pargs == ':')
+ /* No arguments. */
+ return 0;
+
+ return stap_get_probe_argument_count (probe);
+}
+
+static struct value *
+elf_evaluate_probe_argument (struct objfile *objfile,
+ const struct stap_probe *probe,
+ struct frame_info *frame,
+ int n)
+{
+ return stap_evaluate_probe_argument (objfile, probe, frame, n);
+}
+
+static void
+elf_compile_to_ax (struct objfile *objfile,
+ const struct stap_probe *probe,
+ struct agent_expr *expr,
+ struct axs_value *value,
+ int n)
+{
+ stap_compile_to_ax (objfile, probe, expr, value, n);
+}
+
+static void
+elf_symfile_relocate_probe (struct objfile *objfile,
+ struct section_offsets *new_offsets,
+ struct section_offsets *delta)
+{
+ int i;
+ struct stap_probe_per_objfile *p
+ = (struct stap_probe_per_objfile *) objfile_data (objfile,
+ stap_probe_key);
+
+ if (!p)
+ /* No probe to relocate. */
+ return;
+
+ for (i = 0; i < p->stap_num_probes; i++)
+ {
+ p->probes[i].address += ANOFFSET (delta, SECT_OFF_TEXT (objfile));
+ if (p->probes[i].sem_addr)
+ p->probes[i].sem_addr += ANOFFSET (delta, SECT_OFF_DATA (objfile));
+ }
+}
+
+static void
+stap_probe_key_free (struct objfile *objfile, void *d)
+{
+ int i;
+ struct stap_probe_per_objfile *data = (struct stap_probe_per_objfile *) d;
+
+ for (i = 0; i < data->stap_num_probes; i++)
+ stap_free_parsed_args (data->probes[i].parsed_args);
+ xfree (data->probes);
+ xfree (data);
+}
+
+static const struct sym_probe_fns elf_probe_fns =
+{
+ elf_get_probes, /* sym_get_probes */
+ elf_get_probe_argument_count, /* sym_get_probe_argument_count */
+ elf_evaluate_probe_argument, /* sym_evaluate_probe_argument */
+ elf_compile_to_ax, /* sym_compile_to_ax */
+ elf_symfile_relocate_probe, /* sym_relocate_probe */
+};
+
/* Register that we are able to handle ELF object file formats. */
static const struct sym_fns elf_sym_fns =
@@ -1086,6 +1819,7 @@ static const struct sym_fns elf_sym_fns =
elf_symfile_segments, /* Get segment information from a file. */
NULL,
default_symfile_relocate, /* Relocate a debug section. */
+ &elf_probe_fns, /* sym_probe_fns */
&psym_functions
};
@@ -1104,6 +1838,7 @@ static const struct sym_fns elf_sym_fns_lazy_psyms =
elf_symfile_segments, /* Get segment information from a file. */
NULL,
default_symfile_relocate, /* Relocate a debug section. */
+ &elf_probe_fns, /* sym_probe_fns */
&psym_functions
};
@@ -1121,11 +1856,27 @@ static const struct sym_fns elf_sym_fns_gdb_index =
elf_symfile_segments, /* Get segment information from a file. */
NULL,
default_symfile_relocate, /* Relocate a debug section. */
+ &elf_probe_fns, /* sym_probe_fns */
&dwarf2_gdb_index_functions
};
+/* STT_GNU_IFUNC resolver vector to be installed to gnu_ifunc_fns_p. */
+
+static const struct gnu_ifunc_fns elf_gnu_ifunc_fns =
+{
+ elf_gnu_ifunc_resolve_addr,
+ elf_gnu_ifunc_resolve_name,
+ elf_gnu_ifunc_resolver_stop,
+ elf_gnu_ifunc_resolver_return_stop
+};
+
void
_initialize_elfread (void)
{
+ stap_probe_key
+ = register_objfile_data_with_cleanup (NULL, stap_probe_key_free);
add_symtab_fns (&elf_sym_fns);
+
+ elf_objfile_gnu_ifunc_cache_data = register_objfile_data ();
+ gnu_ifunc_fns_p = &elf_gnu_ifunc_fns;
}
diff --git a/gdb/eval.c b/gdb/eval.c
index 09b41a0..7c0a8f9 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -44,6 +44,7 @@
#include "objfiles.h"
#include "python/python.h"
#include "wrapper.h"
+#include "dwarf2loc.h"
#include "gdb_assert.h"
@@ -489,27 +490,217 @@ init_array_element (struct value *array, struct value *element,
}
static struct value *
-value_f90_subarray (struct value *array,
- struct expression *exp, int *pos, enum noside noside)
+value_f90_subarray (struct value *array, struct expression *exp, int *pos,
+ int nargs, enum noside noside)
{
- int pc = (*pos) + 1;
- LONGEST low_bound, high_bound;
- struct type *range = check_typedef (TYPE_INDEX_TYPE (value_type (array)));
- enum f90_range_type range_type = longest_to_int (exp->elts[pc].longconst);
-
- *pos += 3;
-
- if (range_type == LOW_BOUND_DEFAULT || range_type == BOTH_BOUND_DEFAULT)
- low_bound = TYPE_LOW_BOUND (range);
+ /* Type to use for the newly allocated value ARRAY. */
+ struct type *new_array_type;
+
+ /* Type being iterated for each dimension. */
+ struct type *type, *type_last_target;
+
+ /* Pointer in the last holder to the type of current dimension. */
+ struct type **typep = &new_array_type;
+
+ struct subscript_index
+ {
+ enum { SUBSCRIPT_RANGE, SUBSCRIPT_NUMBER } kind;
+ union
+ {
+ struct subscript_range
+ {
+ enum f90_range_type f90_range_type;
+ LONGEST low_bound, high_bound;
+ }
+ range;
+ LONGEST number;
+ };
+ }
+ *subscript_array;
+ struct type **type_array;
+ int i;
+ struct cleanup *old_chain;
+ CORE_ADDR value_byte_address, value_byte_offset = 0;
+ htab_t copied_types;
+ struct value *saved_array;
+
+ old_chain = make_cleanup (null_cleanup, 0);
+ object_address_set (value_raw_address (array));
+
+ if (value_optimized_out (array)
+ || (VALUE_LVAL (array) != not_lval
+ && VALUE_LVAL (array) != lval_memory
+ && VALUE_LVAL (array) != lval_internalvar_component
+ && VALUE_LVAL (array) != lval_internalvar))
+ error (_("value being subranged must be in memory"));
+ type = check_typedef (value_type (array));
+ f_object_address_data_valid_or_error (type);
+
+ copied_types = create_copied_types_hash (NULL);
+ type = copy_type_recursive (type, copied_types);
+ htab_delete (copied_types);
+
+ if (nargs != calc_f77_array_dims (type))
+ error (_("Wrong number of subscripts"));
+
+ if (TYPE_DATA_LOCATION_IS_ADDR (type))
+ {
+ value_byte_address = (TYPE_DATA_LOCATION_ADDR (type)
+ + value_offset (array));
+ TYPE_DATA_LOCATION_IS_ADDR (type) = 0;
+ TYPE_DATA_LOCATION_DWARF_BLOCK (type) = NULL;
+ }
else
- low_bound = value_as_long (evaluate_subexp (NULL_TYPE, exp, pos, noside));
+ {
+ gdb_assert (TYPE_DATA_LOCATION_DWARF_BLOCK (type) == NULL);
+ value_byte_address = value_address (array);
+ }
+
+ new_array_type = type;
+
+ subscript_array = alloca (sizeof (*subscript_array) * nargs);
+
+ gdb_assert (nargs > 0);
+
+ /* Now that we know we have a legal array subscript expression
+ let us actually find out where this element exists in the array. */
+
+ /* Take array indices left to right. */
+ for (i = 0; i < nargs; i++)
+ {
+ struct subscript_index *index = &subscript_array[i];
+
+ if (exp->elts[*pos].opcode == OP_F90_RANGE)
+ {
+ int pc = (*pos) + 1;
+ struct subscript_range *range;
+
+ index->kind = SUBSCRIPT_RANGE;
+ range = &index->range;
+
+ *pos += 3;
+ range->f90_range_type = longest_to_int (exp->elts[pc].longconst);
+
+ if (range->f90_range_type == HIGH_BOUND_DEFAULT
+ || range->f90_range_type == NONE_BOUND_DEFAULT)
+ range->low_bound = value_as_long (evaluate_subexp (NULL_TYPE, exp,
+ pos, noside));
+
+ if (range->f90_range_type == LOW_BOUND_DEFAULT
+ || range->f90_range_type == NONE_BOUND_DEFAULT)
+ range->high_bound = value_as_long (evaluate_subexp (NULL_TYPE, exp,
+ pos, noside));
+ }
+ else
+ {
+ struct value *val;
+
+ index->kind = SUBSCRIPT_NUMBER;
- if (range_type == HIGH_BOUND_DEFAULT || range_type == BOTH_BOUND_DEFAULT)
- high_bound = TYPE_HIGH_BOUND (range);
+ /* Evaluate each subscript; it must be a legal integer in F77. */
+ val = evaluate_subexp_with_coercion (exp, pos, noside);
+ index->number = value_as_long (val);
+ }
+ }
+
+ /* Internal type of array is arranged right to left. */
+ for (i = nargs - 1; i >= 0; i--)
+ {
+ struct subscript_index *index = &subscript_array[i];
+ struct type *range_type = TYPE_INDEX_TYPE (type);
+
+ switch (index->kind)
+ {
+ case SUBSCRIPT_RANGE:
+ {
+ struct subscript_range *range = &index->range;
+ CORE_ADDR byte_offset;
+
+ if (range->f90_range_type == LOW_BOUND_DEFAULT
+ || range->f90_range_type == BOTH_BOUND_DEFAULT)
+ range->low_bound = TYPE_LOW_BOUND (range_type);
+
+ if (range->f90_range_type == HIGH_BOUND_DEFAULT
+ || range->f90_range_type == BOTH_BOUND_DEFAULT)
+ range->high_bound = TYPE_HIGH_BOUND (range_type);
+
+ if (range->low_bound < TYPE_LOW_BOUND (range_type)
+ || (!TYPE_HIGH_BOUND_UNDEFINED (range_type)
+ && range->high_bound > TYPE_HIGH_BOUND (range_type)))
+ error (_("slice out of range"));
+
+ byte_offset = ((range->low_bound - TYPE_LOW_BOUND (range_type))
+ * TYPE_ARRAY_BYTE_STRIDE_VALUE (type));
+ TYPE_LOW_BOUND (range_type) = range->low_bound;
+ TYPE_HIGH_BOUND (range_type) = range->high_bound;
+ if (range->f90_range_type == LOW_BOUND_DEFAULT
+ || range->f90_range_type == NONE_BOUND_DEFAULT)
+ TYPE_HIGH_BOUND_UNDEFINED (range_type) = 0;
+
+ typep = &TYPE_TARGET_TYPE (type);
+ value_byte_offset += byte_offset;
+ type = TYPE_TARGET_TYPE (type);
+ }
+ break;
+
+ case SUBSCRIPT_NUMBER:
+ {
+ CORE_ADDR byte_offset;
+
+ if (index->number < TYPE_LOW_BOUND (range_type)
+ || (!TYPE_HIGH_BOUND_UNDEFINED (range_type)
+ && index->number > TYPE_HIGH_BOUND (range_type)))
+ error (_("no such vector element"));
+
+ byte_offset = ((index->number - TYPE_LOW_BOUND (range_type))
+ * TYPE_ARRAY_BYTE_STRIDE_VALUE (type));
+
+ type = TYPE_TARGET_TYPE (type);
+ *typep = type;
+ value_byte_offset += byte_offset;
+ }
+ break;
+ }
+ }
+
+ type_last_target = type;
+ type_array = alloca (sizeof (*type_array) * nargs);
+ i = 0;
+ for (type = new_array_type; type != type_last_target;
+ type = TYPE_TARGET_TYPE (type))
+ type_array[i++] = type;
+ while (i > 0)
+ {
+ struct type *type = type_array[--i];
+
+ /* Force TYPE_LENGTH (type) recalculation. */
+ TYPE_TARGET_STUB (type) = 1;
+ check_typedef (type);
+ }
+
+ saved_array = array;
+ array = allocate_value_lazy (new_array_type);
+ VALUE_LVAL (array) = VALUE_LVAL (saved_array);
+ if (VALUE_LVAL (saved_array) == lval_internalvar_component)
+ VALUE_LVAL (array) = lval_internalvar;
else
- high_bound = value_as_long (evaluate_subexp (NULL_TYPE, exp, pos, noside));
+ VALUE_LVAL (array) = VALUE_LVAL (saved_array);
+ VALUE_FRAME_ID (array) = VALUE_FRAME_ID (saved_array);
+ if (VALUE_LVAL (array) != lval_internalvar)
+ set_value_address (array, value_byte_address + value_byte_offset);
+
+ if (!value_lazy (saved_array))
+ {
+ allocate_value_contents (array);
+ set_value_lazy (array, 0);
- return value_slice (array, low_bound, high_bound - low_bound + 1);
+ memcpy (value_contents_writeable (array),
+ value_contents (saved_array) + value_byte_offset,
+ TYPE_LENGTH (new_array_type));
+ }
+
+ do_cleanups (old_chain);
+ return array;
}
@@ -790,6 +981,7 @@ evaluate_subexp_standard (struct type *expect_type,
int save_pos1;
struct symbol *function = NULL;
char *function_name = NULL;
+ struct cleanup *old_chain;
pc = (*pos)++;
op = exp->elts[pc].opcode;
@@ -1832,6 +2024,8 @@ evaluate_subexp_standard (struct type *expect_type,
return value_zero (builtin_type (exp->gdbarch)->builtin_int,
not_lval);
}
+ else if (TYPE_GNU_IFUNC (ftype))
+ return allocate_value (TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (ftype)));
else if (TYPE_TARGET_TYPE (ftype))
return allocate_value (TYPE_TARGET_TYPE (ftype));
else
@@ -1860,6 +2054,8 @@ evaluate_subexp_standard (struct type *expect_type,
/* First determine the type code we are dealing with. */
arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ old_chain = make_cleanup (null_cleanup, 0);
+ object_address_set (value_raw_address (arg1));
type = check_typedef (value_type (arg1));
code = TYPE_CODE (type);
@@ -1880,23 +2076,13 @@ evaluate_subexp_standard (struct type *expect_type,
code = TYPE_CODE (type);
}
}
+ do_cleanups (old_chain);
switch (code)
{
case TYPE_CODE_ARRAY:
- if (exp->elts[*pos].opcode == OP_F90_RANGE)
- return value_f90_subarray (arg1, exp, pos, noside);
- else
- goto multi_f77_subscript;
-
case TYPE_CODE_STRING:
- if (exp->elts[*pos].opcode == OP_F90_RANGE)
- return value_f90_subarray (arg1, exp, pos, noside);
- else
- {
- arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
- return value_subscript (arg1, value_as_long (arg2));
- }
+ return value_f90_subarray (arg1, exp, pos, nargs, noside);
case TYPE_CODE_PTR:
case TYPE_CODE_FUNC:
@@ -2335,49 +2521,6 @@ evaluate_subexp_standard (struct type *expect_type,
}
return (arg1);
- multi_f77_subscript:
- {
- LONGEST subscript_array[MAX_FORTRAN_DIMS];
- int ndimensions = 1, i;
- struct value *array = arg1;
-
- if (nargs > MAX_FORTRAN_DIMS)
- error (_("Too many subscripts for F77 (%d Max)"), MAX_FORTRAN_DIMS);
-
- ndimensions = calc_f77_array_dims (type);
-
- if (nargs != ndimensions)
- error (_("Wrong number of subscripts"));
-
- gdb_assert (nargs > 0);
-
- /* Now that we know we have a legal array subscript expression
- let us actually find out where this element exists in the array. */
-
- /* Take array indices left to right. */
- for (i = 0; i < nargs; i++)
- {
- /* Evaluate each subscript; it must be a legal integer in F77. */
- arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
-
- /* Fill in the subscript array. */
-
- subscript_array[i] = value_as_long (arg2);
- }
-
- /* Internal type of array is arranged right to left. */
- for (i = nargs; i > 0; i--)
- {
- struct type *array_type = check_typedef (value_type (array));
- LONGEST index = subscript_array[i - 1];
-
- lower = f77_get_lowerbound (array_type);
- array = value_subscripted_rvalue (array, index, lower);
- }
-
- return array;
- }
-
case BINOP_LOGICAL_AND:
arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
if (noside == EVAL_SKIP)
@@ -2609,15 +2752,23 @@ evaluate_subexp_standard (struct type *expect_type,
if (expect_type && TYPE_CODE (expect_type) == TYPE_CODE_PTR)
expect_type = TYPE_TARGET_TYPE (check_typedef (expect_type));
arg1 = evaluate_subexp (expect_type, exp, pos, noside);
+ old_chain = make_cleanup (null_cleanup, 0);
+ object_address_set (value_raw_address (arg1));
type = check_typedef (value_type (arg1));
if (TYPE_CODE (type) == TYPE_CODE_METHODPTR
|| TYPE_CODE (type) == TYPE_CODE_MEMBERPTR)
error (_("Attempt to dereference pointer "
"to member without an object"));
if (noside == EVAL_SKIP)
- goto nosideret;
+ {
+ do_cleanups (old_chain);
+ goto nosideret;
+ }
if (unop_user_defined_p (op, arg1))
- return value_x_unop (arg1, op, noside);
+ {
+ do_cleanups (old_chain);
+ return value_x_unop (arg1, op, noside);
+ }
else if (noside == EVAL_AVOID_SIDE_EFFECTS)
{
type = check_typedef (value_type (arg1));
@@ -2626,12 +2777,18 @@ evaluate_subexp_standard (struct type *expect_type,
/* In C you can dereference an array to get the 1st elt. */
|| TYPE_CODE (type) == TYPE_CODE_ARRAY
)
- return value_zero (TYPE_TARGET_TYPE (type),
- lval_memory);
+ {
+ do_cleanups (old_chain);
+ return value_zero (TYPE_TARGET_TYPE (type),
+ lval_memory);
+ }
else if (TYPE_CODE (type) == TYPE_CODE_INT)
- /* GDB allows dereferencing an int. */
- return value_zero (builtin_type (exp->gdbarch)->builtin_int,
- lval_memory);
+ {
+ do_cleanups (old_chain);
+ /* GDB allows dereferencing an int. */
+ return value_zero (builtin_type (exp->gdbarch)->builtin_int,
+ lval_memory);
+ }
else
error (_("Attempt to take contents of a non-pointer value."));
}
@@ -2641,9 +2798,14 @@ evaluate_subexp_standard (struct type *expect_type,
do. "long long" variables are rare enough that
BUILTIN_TYPE_LONGEST would seem to be a mistake. */
if (TYPE_CODE (type) == TYPE_CODE_INT)
- return value_at_lazy (builtin_type (exp->gdbarch)->builtin_int,
- (CORE_ADDR) value_as_address (arg1));
- return value_ind (arg1);
+ {
+ do_cleanups (old_chain);
+ return value_at_lazy (builtin_type (exp->gdbarch)->builtin_int,
+ (CORE_ADDR) value_as_address (arg1));
+ }
+ arg1 = value_ind (arg1);
+ do_cleanups (old_chain);
+ return arg1;
case UNOP_ADDR:
/* C++: check for and handle pointer to members. */
@@ -2989,7 +3151,7 @@ evaluate_subexp_with_coercion (struct expression *exp,
{
enum exp_opcode op;
int pc;
- struct value *val;
+ struct value *val = NULL;
struct symbol *var;
struct type *type;
@@ -3000,13 +3162,18 @@ evaluate_subexp_with_coercion (struct expression *exp,
{
case OP_VAR_VALUE:
var = exp->elts[pc + 2].symbol;
+ /* address_of_variable will call object_address_set for check_typedef.
+ Call it only if required as it can error-out on VAR in register. */
+ if (TYPE_DYNAMIC (SYMBOL_TYPE (var)))
+ val = address_of_variable (var, exp->elts[pc + 1].block);
type = check_typedef (SYMBOL_TYPE (var));
if (TYPE_CODE (type) == TYPE_CODE_ARRAY
&& !TYPE_VECTOR (type)
&& CAST_IS_CONVERSION (exp->language_defn))
{
(*pos) += 4;
- val = address_of_variable (var, exp->elts[pc + 1].block);
+ if (!val)
+ val = address_of_variable (var, exp->elts[pc + 1].block);
return value_cast (lookup_pointer_type (TYPE_TARGET_TYPE (type)),
val);
}
@@ -3058,9 +3225,13 @@ evaluate_subexp_for_sizeof (struct expression *exp, int *pos)
case OP_VAR_VALUE:
(*pos) += 4;
- type = check_typedef (SYMBOL_TYPE (exp->elts[pc + 2].symbol));
- return
- value_from_longest (size_type, (LONGEST) TYPE_LENGTH (type));
+ /* We do not need to call read_var_value but the object evaluation may
+ need to have executed object_address_set which needs valid
+ SYMBOL_VALUE_ADDRESS of the symbol. Still VALUE returned by
+ read_var_value we left as lazy. */
+ type = value_type (read_var_value (exp->elts[pc + 2].symbol,
+ deprecated_safe_get_selected_frame ()));
+ return value_from_longest (size_type, (LONGEST) TYPE_LENGTH (type));
default:
val = evaluate_subexp (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
@@ -3091,18 +3262,25 @@ parse_and_eval_type (char *p, int length)
int
calc_f77_array_dims (struct type *array_type)
{
- int ndimen = 1;
- struct type *tmp_type;
+ switch (TYPE_CODE (array_type))
+ {
+ case TYPE_CODE_STRING:
+ return 1;
- if ((TYPE_CODE (array_type) != TYPE_CODE_ARRAY))
- error (_("Can't get dimensions for a non-array type"));
+ case TYPE_CODE_ARRAY:
+ {
+ int ndimen = 1;
- tmp_type = array_type;
+ while ((array_type = TYPE_TARGET_TYPE (array_type)))
+ {
+ if (TYPE_CODE (array_type) == TYPE_CODE_ARRAY)
+ ++ndimen;
+ }
+ return ndimen;
+ }
- while ((tmp_type = TYPE_TARGET_TYPE (tmp_type)))
- {
- if (TYPE_CODE (tmp_type) == TYPE_CODE_ARRAY)
- ++ndimen;
+ default:
+ error (_("Can't get dimensions for a non-array/non-string type"));
}
- return ndimen;
+
}
diff --git a/gdb/f-exp.y b/gdb/f-exp.y
index d9cf3cf..3e11e57 100644
--- a/gdb/f-exp.y
+++ b/gdb/f-exp.y
@@ -293,7 +293,9 @@ arglist : subrange
{ arglist_len = 1; }
;
-arglist : arglist ',' exp %prec ABOVE_COMMA
+arglist : arglist ',' exp %prec ABOVE_COMMA
+ { arglist_len++; }
+ | arglist ',' subrange %prec ABOVE_COMMA
{ arglist_len++; }
;
diff --git a/gdb/f-lang.h b/gdb/f-lang.h
index 8043577..94a5f31 100644
--- a/gdb/f-lang.h
+++ b/gdb/f-lang.h
@@ -28,6 +28,10 @@ extern void f_error (char *); /* Defined in f-exp.y */
extern void f_print_type (struct type *, const char *, struct ui_file *, int,
int);
+extern const char *f_object_address_data_valid_print_to_stream
+ (struct type *type, struct ui_file *stream);
+extern void f_object_address_data_valid_or_error (struct type *type);
+
extern int f_val_print (struct type *, const gdb_byte *, int, CORE_ADDR,
struct ui_file *, int,
const struct value *,
diff --git a/gdb/f-typeprint.c b/gdb/f-typeprint.c
index ad988d2..985fef6 100644
--- a/gdb/f-typeprint.c
+++ b/gdb/f-typeprint.c
@@ -32,7 +32,7 @@
#include "gdbcore.h"
#include "target.h"
#include "f-lang.h"
-
+#include "dwarf2loc.h"
#include "gdb_string.h"
#include <errno.h>
@@ -49,6 +49,34 @@ void f_type_print_varspec_prefix (struct type *, struct ui_file *,
void f_type_print_base (struct type *, struct ui_file *, int, int);
+const char *
+f_object_address_data_valid_print_to_stream (struct type *type,
+ struct ui_file *stream)
+{
+ const char *msg;
+
+ msg = object_address_data_not_valid (type);
+ if (msg != NULL)
+ {
+ /* Assuming the content printed to STREAM should not be localized. */
+ fprintf_filtered (stream, "<%s>", msg);
+ }
+
+ return msg;
+}
+
+void
+f_object_address_data_valid_or_error (struct type *type)
+{
+ const char *msg;
+
+ msg = object_address_data_not_valid (type);
+ if (msg != NULL)
+ {
+ error (_("Cannot access it because the %s."), _(msg));
+ }
+}
+
/* LEVEL is the depth to indent lines by. */
void
@@ -58,6 +86,9 @@ f_print_type (struct type *type, const char *varstring, struct ui_file *stream,
enum type_code code;
int demangled_args;
+ if (f_object_address_data_valid_print_to_stream (type, stream) != NULL)
+ return;
+
f_type_print_base (type, stream, show, level);
code = TYPE_CODE (type);
if ((varstring != NULL && *varstring != '\0')
@@ -165,6 +196,9 @@ f_type_print_varspec_suffix (struct type *type, struct ui_file *stream,
QUIT;
+ if (TYPE_CODE (type) != TYPE_CODE_TYPEDEF)
+ CHECK_TYPEDEF (type);
+
switch (TYPE_CODE (type))
{
case TYPE_CODE_ARRAY:
diff --git a/gdb/f-valprint.c b/gdb/f-valprint.c
index 3280ddc..128d6bc 100644
--- a/gdb/f-valprint.c
+++ b/gdb/f-valprint.c
@@ -54,15 +54,17 @@ int f77_array_offset_tbl[MAX_FORTRAN_DIMS + 1][2];
/* The following macro gives us the size of the nth dimension, Where
n is 1 based. */
-#define F77_DIM_SIZE(n) (f77_array_offset_tbl[n][1])
+#define F77_DIM_COUNT(n) (f77_array_offset_tbl[n][1])
-/* The following gives us the offset for row n where n is 1-based. */
+/* The following gives us the element size for row n where n is 1-based. */
-#define F77_DIM_OFFSET(n) (f77_array_offset_tbl[n][0])
+#define F77_DIM_BYTE_STRIDE(n) (f77_array_offset_tbl[n][0])
int
f77_get_lowerbound (struct type *type)
{
+ f_object_address_data_valid_or_error (type);
+
if (TYPE_ARRAY_LOWER_BOUND_IS_UNDEFINED (type))
error (_("Lower bound may not be '*' in F77"));
@@ -72,14 +74,17 @@ f77_get_lowerbound (struct type *type)
int
f77_get_upperbound (struct type *type)
{
+ f_object_address_data_valid_or_error (type);
+
if (TYPE_ARRAY_UPPER_BOUND_IS_UNDEFINED (type))
{
- /* We have an assumed size array on our hands. Assume that
- upper_bound == lower_bound so that we show at least 1 element.
- If the user wants to see more elements, let him manually ask for 'em
- and we'll subscript the array and show him. */
+ /* We have an assumed size array on our hands. As type_length_get
+ already assumes a length zero of arrays with underfined bounds VALADDR
+ passed to the Fortran functions does not contained the real inferior
+ memory content. User should request printing of specific array
+ elements instead. */
- return f77_get_lowerbound (type);
+ return f77_get_lowerbound (type) - 1;
}
return TYPE_ARRAY_UPPER_BOUND_VALUE (type);
@@ -135,24 +140,29 @@ f77_create_arrayprint_offset_tbl (struct type *type, struct ui_file *stream)
upper = f77_get_upperbound (tmp_type);
lower = f77_get_lowerbound (tmp_type);
- F77_DIM_SIZE (ndimen) = upper - lower + 1;
+ F77_DIM_COUNT (ndimen) = upper - lower + 1;
+
+ F77_DIM_BYTE_STRIDE (ndimen) =
+ TYPE_ARRAY_BYTE_STRIDE_VALUE (tmp_type);
tmp_type = TYPE_TARGET_TYPE (tmp_type);
ndimen++;
}
- /* Now we multiply eltlen by all the offsets, so that later we
+ /* Now we multiply eltlen by all the BYTE_STRIDEs, so that later we
can print out array elements correctly. Up till now we
- know an offset to apply to get the item but we also
+ know an eltlen to apply to get the item but we also
have to know how much to add to get to the next item. */
ndimen--;
eltlen = TYPE_LENGTH (tmp_type);
- F77_DIM_OFFSET (ndimen) = eltlen;
+ if (F77_DIM_BYTE_STRIDE (ndimen) == 0)
+ F77_DIM_BYTE_STRIDE (ndimen) = eltlen;
while (--ndimen > 0)
{
- eltlen *= F77_DIM_SIZE (ndimen + 1);
- F77_DIM_OFFSET (ndimen) = eltlen;
+ eltlen *= F77_DIM_COUNT (ndimen + 1);
+ if (F77_DIM_BYTE_STRIDE (ndimen) == 0)
+ F77_DIM_BYTE_STRIDE (ndimen) = eltlen;
}
}
@@ -174,37 +184,35 @@ f77_print_array_1 (int nss, int ndimensions, struct type *type,
if (nss != ndimensions)
{
- for (i = 0;
- (i < F77_DIM_SIZE (nss) && (*elts) < options->print_max);
- i++)
+ for (i = 0; (i < F77_DIM_COUNT (nss) && (*elts) < options->print_max); i++)
{
fprintf_filtered (stream, "( ");
f77_print_array_1 (nss + 1, ndimensions, TYPE_TARGET_TYPE (type),
valaddr,
- embedded_offset + i * F77_DIM_OFFSET (nss),
+ embedded_offset + i * F77_DIM_BYTE_STRIDE (nss),
address,
stream, recurse, val, options, elts);
fprintf_filtered (stream, ") ");
}
- if (*elts >= options->print_max && i < F77_DIM_SIZE (nss))
+ if (*elts >= options->print_max && i < F77_DIM_COUNT (nss))
fprintf_filtered (stream, "...");
}
else
{
- for (i = 0; i < F77_DIM_SIZE (nss) && (*elts) < options->print_max;
+ for (i = 0; i < F77_DIM_COUNT (nss) && (*elts) < options->print_max;
i++, (*elts)++)
{
val_print (TYPE_TARGET_TYPE (type),
valaddr,
- embedded_offset + i * F77_DIM_OFFSET (ndimensions),
+ embedded_offset + i * F77_DIM_BYTE_STRIDE (ndimensions),
address, stream, recurse,
val, options, current_language);
- if (i != (F77_DIM_SIZE (nss) - 1))
+ if (i != (F77_DIM_COUNT (nss) - 1))
fprintf_filtered (stream, ", ");
if ((*elts == options->print_max - 1)
- && (i != (F77_DIM_SIZE (nss) - 1)))
+ && (i != (F77_DIM_COUNT (nss) - 1)))
fprintf_filtered (stream, "...");
}
}
@@ -260,6 +268,9 @@ f_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset,
CORE_ADDR addr;
int index;
+ if (f_object_address_data_valid_print_to_stream (type, stream) != NULL)
+ return 0;
+
CHECK_TYPEDEF (type);
switch (TYPE_CODE (type))
{
diff --git a/gdb/findvar.c b/gdb/findvar.c
index 2b361ef..01e1c0d 100644
--- a/gdb/findvar.c
+++ b/gdb/findvar.c
@@ -35,6 +35,7 @@
#include "user-regs.h"
#include "block.h"
#include "objfiles.h"
+#include "dwarf2loc.h"
/* Basic byte-swapping routines. All 'extract' functions return a
host-format integer from a target-format integer at ADDR which is
@@ -408,8 +409,11 @@ symbol_read_needs_frame (struct symbol *sym)
/* Given a struct symbol for a variable,
and a stack frame id, read the value of the variable
- and return a (pointer to a) struct value containing the value.
- If the variable cannot be found, return a zero pointer. */
+ and return a (pointer to a) struct value containing the value.
+ If the variable cannot be found, return a zero pointer.
+ We have to first find the address of the variable before allocating struct
+ value to return as its size may depend on DW_OP_PUSH_OBJECT_ADDRESS possibly
+ used by its type. */
struct value *
read_var_value (struct symbol *var, struct frame_info *frame)
@@ -417,16 +421,6 @@ read_var_value (struct symbol *var, struct frame_info *frame)
struct value *v;
struct type *type = SYMBOL_TYPE (var);
CORE_ADDR addr;
- int len;
-
- /* Call check_typedef on our type to make sure that, if TYPE is
- a TYPE_CODE_TYPEDEF, its length is set to the length of the target type
- instead of zero. However, we do not replace the typedef type by the
- target type, because we want to keep the typedef in order to be able to
- set the returned value type description correctly. */
- check_typedef (type);
-
- len = TYPE_LENGTH (type);
if (symbol_read_needs_frame (var))
gdb_assert (frame);
@@ -436,7 +430,7 @@ read_var_value (struct symbol *var, struct frame_info *frame)
case LOC_CONST:
/* Put the constant back in target format. */
v = allocate_value (type);
- store_signed_integer (value_contents_raw (v), len,
+ store_signed_integer (value_contents_raw (v), TYPE_LENGTH (type),
gdbarch_byte_order (get_type_arch (type)),
(LONGEST) SYMBOL_VALUE (var));
VALUE_LVAL (v) = not_lval;
@@ -461,12 +455,12 @@ read_var_value (struct symbol *var, struct frame_info *frame)
case LOC_CONST_BYTES:
v = allocate_value (type);
- memcpy (value_contents_raw (v), SYMBOL_VALUE_BYTES (var), len);
+ memcpy (value_contents_raw (v), SYMBOL_VALUE_BYTES (var),
+ TYPE_LENGTH (type));
VALUE_LVAL (v) = not_lval;
return v;
case LOC_STATIC:
- v = allocate_value_lazy (type);
if (overlay_debugging)
addr = symbol_overlayed_address (SYMBOL_VALUE_ADDRESS (var),
SYMBOL_OBJ_SECTION (var));
@@ -479,7 +473,6 @@ read_var_value (struct symbol *var, struct frame_info *frame)
if (!addr)
return 0;
addr += SYMBOL_VALUE (var);
- v = allocate_value_lazy (type);
break;
case LOC_REF_ARG:
@@ -493,14 +486,12 @@ read_var_value (struct symbol *var, struct frame_info *frame)
argref += SYMBOL_VALUE (var);
ref = value_at (lookup_pointer_type (type), argref);
addr = value_as_address (ref);
- v = allocate_value_lazy (type);
break;
}
case LOC_LOCAL:
addr = get_frame_locals_address (frame);
addr += SYMBOL_VALUE (var);
- v = allocate_value_lazy (type);
break;
case LOC_TYPEDEF:
@@ -508,7 +499,6 @@ read_var_value (struct symbol *var, struct frame_info *frame)
break;
case LOC_BLOCK:
- v = allocate_value_lazy (type);
if (overlay_debugging)
addr = symbol_overlayed_address
(BLOCK_START (SYMBOL_BLOCK_VALUE (var)), SYMBOL_OBJ_SECTION (var));
@@ -533,7 +523,6 @@ read_var_value (struct symbol *var, struct frame_info *frame)
error (_("Value of register variable not available."));
addr = value_as_address (regval);
- v = allocate_value_lazy (type);
}
else
{
@@ -572,7 +561,6 @@ read_var_value (struct symbol *var, struct frame_info *frame)
if (obj_section
&& (obj_section->the_bfd_section->flags & SEC_THREAD_LOCAL) != 0)
addr = target_translate_tls_address (obj_section->objfile, addr);
- v = allocate_value_lazy (type);
}
break;
@@ -587,6 +575,10 @@ read_var_value (struct symbol *var, struct frame_info *frame)
break;
}
+ /* ADDR is set here for ALLOCATE_VALUE's CHECK_TYPEDEF for
+ DW_OP_PUSH_OBJECT_ADDRESS. */
+ object_address_set (addr);
+ v = allocate_value_lazy (type);
VALUE_LVAL (v) = lval_memory;
set_value_address (v, addr);
return v;
@@ -626,11 +618,12 @@ struct value *
value_from_register (struct type *type, int regnum, struct frame_info *frame)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
- struct type *type1 = check_typedef (type);
struct value *v;
int optim, unavail, ok;
- if (gdbarch_convert_register_p (gdbarch, regnum, type1))
+ type = check_typedef (type);
+
+ if (gdbarch_convert_register_p (gdbarch, regnum, type))
{
/* The ISA/ABI need to something weird when obtaining the
specified value from this register. It might need to
@@ -643,7 +636,7 @@ value_from_register (struct type *type, int regnum, struct frame_info *frame)
VALUE_LVAL (v) = lval_register;
VALUE_FRAME_ID (v) = get_frame_id (frame);
VALUE_REGNUM (v) = regnum;
- ok = gdbarch_register_to_value (gdbarch, frame, regnum, type1,
+ ok = gdbarch_register_to_value (gdbarch, frame, regnum, type,
value_contents_raw (v), &optim,
&unavail);
}
diff --git a/gdb/gdbinit.in b/gdb/gdbinit.in
index ffb7f53..a2e7e94 100644
--- a/gdb/gdbinit.in
+++ b/gdb/gdbinit.in
@@ -1,5 +1,15 @@
echo Setting up the environment for debugging gdb.\n
+# Set up the Python library and "require" command.
+python
+from os.path import abspath
+gdb.datadir = abspath ('@srcdir@/python/lib')
+gdb.pythonlibdir = gdb.datadir
+gdb.__path__ = [gdb.datadir + '/gdb']
+sys.path.insert(0, gdb.datadir)
+end
+source @srcdir@/python/lib/gdb/__init__.py
+
set complaints 1
b internal_error
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 91fafa2..eda2506 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -39,6 +39,9 @@
#include "cp-abi.h"
#include "gdb_assert.h"
#include "hashtab.h"
+#include "observer.h"
+#include "dwarf2expr.h"
+#include "dwarf2loc.h"
/* Initialize BADNESS constants. */
@@ -144,7 +147,16 @@ static void print_bit_vector (B_TYPE *, int);
static void print_arg_types (struct field *, int, int);
static void dump_fn_fieldlists (struct type *, int);
static void print_cplus_stuff (struct type *, int);
+static LONGEST type_length_get (struct type *type, struct type *target_type,
+ int full_span);
+#if 0
+/* The hash table holding all discardable `struct type *' references. */
+static htab_t type_discardable_table;
+
+/* Current type_discardable_check pass used for TYPE_DISCARDABLE_AGE. */
+static int type_discardable_age_current;
+#endif
/* Allocate a new OBJFILE-associated type structure and fill it
with some defaults. Space for the type structure is allocated
@@ -175,6 +187,43 @@ alloc_type (struct objfile *objfile)
return type;
}
+#if 0
+/* Declare TYPE as discardable on next garbage collection by free_all_types.
+ You must call type_mark_used during each free_all_types to protect TYPE from
+ being deallocated. */
+
+static void
+set_type_as_discardable (struct type *type)
+{
+ void **slot;
+
+ gdb_assert (!TYPE_DISCARDABLE (type));
+
+ TYPE_DISCARDABLE (type) = 1;
+ TYPE_DISCARDABLE_AGE (type) = type_discardable_age_current;
+
+ slot = htab_find_slot (type_discardable_table, type, INSERT);
+ gdb_assert (!*slot);
+ *slot = type;
+}
+#endif
+
+/* Allocate a new type like alloc_type but preserve for it the discardability
+ state of PARENT_TYPE. */
+
+static struct type *
+alloc_type_as_parent (struct type *parent_type)
+{
+ struct type *new_type = alloc_type_copy (parent_type);
+
+#if 0
+ if (TYPE_DISCARDABLE (parent_type))
+ set_type_as_discardable (new_type);
+#endif
+
+ return new_type;
+}
+
/* Allocate a new GDBARCH-associated type structure and fill it
with some defaults. Space for the type structure is allocated
on the heap. */
@@ -300,7 +349,7 @@ make_pointer_type (struct type *type, struct type **typeptr)
if (typeptr == 0 || *typeptr == 0) /* We'll need to allocate one. */
{
- ntype = alloc_type_copy (type);
+ ntype = alloc_type_as_parent (type);
if (typeptr)
*typeptr = ntype;
}
@@ -377,7 +426,7 @@ make_reference_type (struct type *type, struct type **typeptr)
if (typeptr == 0 || *typeptr == 0) /* We'll need to allocate one. */
{
- ntype = alloc_type_copy (type);
+ ntype = alloc_type_as_parent (type);
if (typeptr)
*typeptr = ntype;
}
@@ -748,6 +797,7 @@ create_range_type (struct type *result_type, struct type *index_type,
TYPE_ZALLOC (result_type, sizeof (struct range_bounds));
TYPE_LOW_BOUND (result_type) = low_bound;
TYPE_HIGH_BOUND (result_type) = high_bound;
+ TYPE_BYTE_STRIDE (result_type) = 0;
if (low_bound >= 0)
TYPE_UNSIGNED (result_type) = 1;
@@ -891,26 +941,31 @@ create_array_type (struct type *result_type,
TYPE_CODE (result_type) = TYPE_CODE_ARRAY;
TYPE_TARGET_TYPE (result_type) = element_type;
- if (get_discrete_bounds (range_type, &low_bound, &high_bound) < 0)
- low_bound = high_bound = 0;
- CHECK_TYPEDEF (element_type);
- /* Be careful when setting the array length. Ada arrays can be
- empty arrays with the high_bound being smaller than the low_bound.
- In such cases, the array length should be zero. */
- if (high_bound < low_bound)
- TYPE_LENGTH (result_type) = 0;
- else
- TYPE_LENGTH (result_type) =
- TYPE_LENGTH (element_type) * (high_bound - low_bound + 1);
TYPE_NFIELDS (result_type) = 1;
TYPE_FIELDS (result_type) =
(struct field *) TYPE_ZALLOC (result_type, sizeof (struct field));
TYPE_INDEX_TYPE (result_type) = range_type;
TYPE_VPTR_FIELDNO (result_type) = -1;
- /* TYPE_FLAG_TARGET_STUB will take care of zero length arrays. */
+ /* DWARF blocks may depend on runtime information like
+ DW_OP_PUSH_OBJECT_ADDRESS not being available during the
+ CREATE_ARRAY_TYPE time. */
+ if (TYPE_RANGE_DATA (range_type)->low.kind != RANGE_BOUND_KIND_CONSTANT
+ || TYPE_RANGE_DATA (range_type)->high.kind != RANGE_BOUND_KIND_CONSTANT
+ || TYPE_DYNAMIC (element_type))
+ TYPE_LENGTH (result_type) = 0;
+ else
+ {
+ CHECK_TYPEDEF (element_type);
+ TYPE_LENGTH (result_type) = type_length_get (result_type, element_type,
+ 0);
+ }
if (TYPE_LENGTH (result_type) == 0)
- TYPE_TARGET_STUB (result_type) = 1;
+ {
+ /* The real size will be computed for specific instances by
+ CHECK_TYPEDEF. */
+ TYPE_TARGET_STUB (result_type) = 1;
+ }
return result_type;
}
@@ -1413,6 +1468,105 @@ stub_noname_complaint (void)
complaint (&symfile_complaints, _("stub type has NULL name"));
}
+/* Calculate the memory length of array TYPE.
+
+ TARGET_TYPE should be set to `check_typedef (TYPE_TARGET_TYPE (type))' as
+ a performance hint. Feel free to pass NULL. Set FULL_SPAN to return the
+ size incl. the possible padding of the last element - it may differ from the
+ cleared FULL_SPAN return value (the expected SIZEOF) for non-zero
+ TYPE_BYTE_STRIDE values. */
+
+static LONGEST
+type_length_get (struct type *type, struct type *target_type, int full_span)
+{
+ struct type *range_type;
+ LONGEST byte_stride = 0; /* `= 0' for a false GCC warning. */
+ LONGEST count, element_size, retval;
+
+ if (TYPE_CODE (type) != TYPE_CODE_ARRAY
+ && TYPE_CODE (type) != TYPE_CODE_STRING)
+ return TYPE_LENGTH (type);
+
+ /* Avoid executing TYPE_HIGH_BOUND for invalid (unallocated/unassociated)
+ Fortran arrays. The allocated data will never be used so they can be
+ zero-length. */
+ if (object_address_data_not_valid (type))
+ return 0;
+
+ range_type = TYPE_INDEX_TYPE (type);
+ if (TYPE_LOW_BOUND_UNDEFINED (range_type)
+ || TYPE_HIGH_BOUND_UNDEFINED (range_type))
+ return 0;
+ count = TYPE_HIGH_BOUND (range_type) - TYPE_LOW_BOUND (range_type) + 1;
+ /* It may happen for wrong DWARF annotations returning garbage data. */
+ if (count < 0)
+ warning (_("Range for type %s has invalid bounds %s..%s"),
+ TYPE_NAME (type), plongest (TYPE_LOW_BOUND (range_type)),
+ plongest (TYPE_HIGH_BOUND (range_type)));
+ /* The code below does not handle count == 0 right. */
+ if (count <= 0)
+ return 0;
+ if (full_span || count > 1)
+ {
+ /* We do not use TYPE_ARRAY_BYTE_STRIDE_VALUE (type) here as we want to
+ force FULL_SPAN to 1. */
+ byte_stride = TYPE_BYTE_STRIDE (range_type);
+ if (byte_stride == 0)
+ {
+ if (target_type == NULL)
+ target_type = check_typedef (TYPE_TARGET_TYPE (type));
+ byte_stride = type_length_get (target_type, NULL, 1);
+ }
+ }
+
+ /* For now, we conservatively take the array length to be 0 if its length
+ exceeds UINT_MAX. The code below assumes that for x < 0,
+ (ULONGEST) x == -x + ULONGEST_MAX + 1, which is technically not guaranteed
+ by C, but is usually true (because it would be true if x were unsigned
+ with its high-order bit on). It uses the fact that high_bound-low_bound is
+ always representable in ULONGEST and that if high_bound-low_bound+1
+ overflows, it overflows to 0. We must change these tests if we decide to
+ increase the representation of TYPE_LENGTH from unsigned int to ULONGEST.
+ */
+
+ if (full_span)
+ {
+ retval = count * byte_stride;
+ if (count == 0 || retval / count != byte_stride || retval > UINT_MAX)
+ retval = 0;
+ return retval;
+ }
+ if (target_type == NULL)
+ target_type = check_typedef (TYPE_TARGET_TYPE (type));
+ element_size = type_length_get (target_type, NULL, 1);
+ retval = (count - 1) * byte_stride + element_size;
+ if (retval < element_size
+ || (byte_stride != 0
+ && (retval - element_size) / byte_stride != count - 1)
+ || retval > UINT_MAX)
+ retval = 0;
+ return retval;
+}
+
+/* Prepare TYPE after being read in by the backend. Currently this function
+ only propagates the TYPE_DYNAMIC flag. */
+
+void
+finalize_type (struct type *type)
+{
+ int i;
+
+ for (i = 0; i < TYPE_NFIELDS (type); ++i)
+ if (TYPE_FIELD_TYPE (type, i) && TYPE_DYNAMIC (TYPE_FIELD_TYPE (type, i)))
+ break;
+
+ /* FIXME: cplus_stuff is ignored here. */
+ if (i < TYPE_NFIELDS (type)
+ || (TYPE_VPTR_BASETYPE (type) && TYPE_DYNAMIC (TYPE_VPTR_BASETYPE (type)))
+ || (TYPE_TARGET_TYPE (type) && TYPE_DYNAMIC (TYPE_TARGET_TYPE (type))))
+ TYPE_DYNAMIC (type) = 1;
+}
+
/* Find the real type of TYPE. This function returns the real type,
after removing all layers of typedefs, and completing opaque or stub
types. Completion changes the TYPE argument, but stripping of
@@ -1575,52 +1729,37 @@ check_typedef (struct type *type)
}
}
- if (TYPE_TARGET_STUB (type))
+ /* copy_type_recursive automatically makes the resulting type containing only
+ constant values expected by the callers of this function. */
+ if (TYPE_DYNAMIC (type))
+ {
+ htab_t copied_types;
+
+ copied_types = create_copied_types_hash (NULL);
+ type = copy_type_recursive (type, copied_types);
+ htab_delete (copied_types);
+
+ gdb_assert (TYPE_DYNAMIC (type) == 0);
+ /* Force TYPE_LENGTH (type) recalculation. */
+ TYPE_DYNAMIC (type) = 1;
+ }
+
+ if (TYPE_TARGET_STUB (type) || TYPE_DYNAMIC (type))
{
- struct type *range_type;
struct type *target_type = check_typedef (TYPE_TARGET_TYPE (type));
+ if (TYPE_DYNAMIC (type))
+ TYPE_TARGET_TYPE (type) = target_type;
if (TYPE_STUB (target_type) || TYPE_TARGET_STUB (target_type))
{
/* Nothing we can do. */
}
else if (TYPE_CODE (type) == TYPE_CODE_ARRAY
- && TYPE_NFIELDS (type) == 1
- && (TYPE_CODE (range_type = TYPE_INDEX_TYPE (type))
- == TYPE_CODE_RANGE))
+ || TYPE_CODE (type) == TYPE_CODE_STRING)
{
/* Now recompute the length of the array type, based on its
- number of elements and the target type's length.
- Watch out for Ada null Ada arrays where the high bound
- is smaller than the low bound. */
- const LONGEST low_bound = TYPE_LOW_BOUND (range_type);
- const LONGEST high_bound = TYPE_HIGH_BOUND (range_type);
- ULONGEST len;
-
- if (high_bound < low_bound)
- len = 0;
- else
- {
- /* For now, we conservatively take the array length to be 0
- if its length exceeds UINT_MAX. The code below assumes
- that for x < 0, (ULONGEST) x == -x + ULONGEST_MAX + 1,
- which is technically not guaranteed by C, but is usually true
- (because it would be true if x were unsigned with its
- high-order bit on). It uses the fact that
- high_bound-low_bound is always representable in
- ULONGEST and that if high_bound-low_bound+1 overflows,
- it overflows to 0. We must change these tests if we
- decide to increase the representation of TYPE_LENGTH
- from unsigned int to ULONGEST. */
- ULONGEST ulow = low_bound, uhigh = high_bound;
- ULONGEST tlen = TYPE_LENGTH (target_type);
-
- len = tlen * (uhigh - ulow + 1);
- if (tlen == 0 || (len / tlen - 1 + ulow) != uhigh
- || len > UINT_MAX)
- len = 0;
- }
- TYPE_LENGTH (type) = len;
+ number of elements and the target type's length. */
+ TYPE_LENGTH (type) = type_length_get (type, target_type, 0);
TYPE_TARGET_STUB (type) = 0;
}
else if (TYPE_CODE (type) == TYPE_CODE_RANGE)
@@ -1628,6 +1767,7 @@ check_typedef (struct type *type)
TYPE_LENGTH (type) = TYPE_LENGTH (target_type);
TYPE_TARGET_STUB (type) = 0;
}
+ TYPE_DYNAMIC (type) = 0;
}
type = make_qualified_type (type, instance_flags, NULL);
@@ -1902,6 +2042,8 @@ init_type (enum type_code code, int length, int flags,
TYPE_STUB_SUPPORTED (type) = 1;
if (flags & TYPE_FLAG_FIXED_INSTANCE)
TYPE_FIXED_INSTANCE (type) = 1;
+ if (flags & TYPE_FLAG_GNU_IFUNC)
+ TYPE_GNU_IFUNC (type) = 1;
if (name)
TYPE_NAME (type) = obsavestring (name, strlen (name),
@@ -3264,33 +3406,42 @@ type_pair_eq (const void *item_lhs, const void *item_rhs)
}
/* Allocate the hash table used by copy_type_recursive to walk
- types without duplicates. We use OBJFILE's obstack, because
- OBJFILE is about to be deleted. */
+ types without duplicates. */
htab_t
create_copied_types_hash (struct objfile *objfile)
{
- return htab_create_alloc_ex (1, type_pair_hash, type_pair_eq,
- NULL, &objfile->objfile_obstack,
- hashtab_obstack_allocate,
- dummy_obstack_deallocate);
+ if (objfile == NULL)
+ {
+ /* NULL OBJFILE is for TYPE_DYNAMIC types already contained in
+ OBJFILE_MALLOC memory, such as those from VALUE_HISTORY_CHAIN. Table
+ element entries get allocated by xmalloc - so use xfree. */
+ return htab_create (1, type_pair_hash, type_pair_eq, xfree);
+ }
+ else
+ {
+ /* Use OBJFILE's obstack, because OBJFILE is about to be deleted. Table
+ element entries get allocated by xmalloc - so use xfree. */
+ return htab_create_alloc_ex (1, type_pair_hash, type_pair_eq,
+ xfree, &objfile->objfile_obstack,
+ hashtab_obstack_allocate,
+ dummy_obstack_deallocate);
+ }
}
-/* Recursively copy (deep copy) TYPE, if it is associated with
- OBJFILE. Return a new type allocated using malloc, a saved type if
- we have already visited TYPE (using COPIED_TYPES), or TYPE if it is
- not associated with OBJFILE. */
+/* A helper for copy_type_recursive. This does all the work. OBJFILE is used
+ only for an assertion checking. */
-struct type *
-copy_type_recursive (struct objfile *objfile,
- struct type *type,
- htab_t copied_types)
+static struct type *
+copy_type_recursive_1 (struct objfile *objfile,
+ struct type *type,
+ htab_t copied_types)
{
struct type_pair *stored, pair;
void **slot;
struct type *new_type;
- if (! TYPE_OBJFILE_OWNED (type))
+ if (! TYPE_OBJFILE_OWNED (type) && !TYPE_DYNAMIC (type))
return type;
/* This type shouldn't be pointing to any types in other objfiles;
@@ -3305,9 +3456,10 @@ copy_type_recursive (struct objfile *objfile,
new_type = alloc_type_arch (get_type_arch (type));
/* We must add the new type to the hash table immediately, in case
- we encounter this type again during a recursive call below. */
- stored
- = obstack_alloc (&objfile->objfile_obstack, sizeof (struct type_pair));
+ we encounter this type again during a recursive call below. Memory could
+ be allocated from OBJFILE in the case we will be removing OBJFILE, this
+ optimization is missed and xfree is called for it from COPIED_TYPES. */
+ stored = xmalloc (sizeof (*stored));
stored->old = type;
stored->new = new_type;
*slot = stored;
@@ -3318,6 +3470,21 @@ copy_type_recursive (struct objfile *objfile,
TYPE_OBJFILE_OWNED (new_type) = 0;
TYPE_OWNER (new_type).gdbarch = get_type_arch (type);
+#if 0
+ /* TYPE_MAIN_TYPE memory copy above rewrote the TYPE_DISCARDABLE flag so we
+ need to initialize it again. And even if TYPE was already discardable
+ NEW_TYPE so far is not registered in TYPE_DISCARDABLE_TABLE. */
+ TYPE_DISCARDABLE (new_type) = 0;
+ set_type_as_discardable (new_type);
+#endif
+
+ /* Pre-clear the fields processed by delete_main_type. If DWARF block
+ evaluations below call error we would leave an unfreeable TYPE. */
+ TYPE_TARGET_TYPE (new_type) = NULL;
+ TYPE_VPTR_BASETYPE (new_type) = NULL;
+ TYPE_NFIELDS (new_type) = 0;
+ TYPE_FIELDS (new_type) = NULL;
+
if (TYPE_NAME (type))
TYPE_NAME (new_type) = xstrdup (TYPE_NAME (type));
if (TYPE_TAG_NAME (type))
@@ -3326,12 +3493,48 @@ copy_type_recursive (struct objfile *objfile,
TYPE_INSTANCE_FLAGS (new_type) = TYPE_INSTANCE_FLAGS (type);
TYPE_LENGTH (new_type) = TYPE_LENGTH (type);
+ if (TYPE_ALLOCATED (new_type))
+ {
+ gdb_assert (!TYPE_NOT_ALLOCATED (new_type));
+
+ if (!dwarf_locexpr_baton_eval (TYPE_ALLOCATED (new_type)))
+ TYPE_NOT_ALLOCATED (new_type) = 1;
+ TYPE_ALLOCATED (new_type) = NULL;
+ }
+
+ if (TYPE_ASSOCIATED (new_type))
+ {
+ gdb_assert (!TYPE_NOT_ASSOCIATED (new_type));
+
+ if (!dwarf_locexpr_baton_eval (TYPE_ASSOCIATED (new_type)))
+ TYPE_NOT_ASSOCIATED (new_type) = 1;
+ TYPE_ASSOCIATED (new_type) = NULL;
+ }
+
+ if (!TYPE_DATA_LOCATION_IS_ADDR (new_type)
+ && TYPE_DATA_LOCATION_DWARF_BLOCK (new_type))
+ {
+ if (TYPE_NOT_ALLOCATED (new_type)
+ || TYPE_NOT_ASSOCIATED (new_type))
+ TYPE_DATA_LOCATION_DWARF_BLOCK (new_type) = NULL;
+ else
+ {
+ TYPE_DATA_LOCATION_IS_ADDR (new_type) = 1;
+ TYPE_DATA_LOCATION_ADDR (new_type) = dwarf_locexpr_baton_eval
+ (TYPE_DATA_LOCATION_DWARF_BLOCK (new_type));
+ }
+ }
+
/* Copy the fields. */
if (TYPE_NFIELDS (type))
{
int i, nfields;
+ /* TYPE_CODE_RANGE uses TYPE_RANGE_DATA of the union with TYPE_FIELDS. */
+ gdb_assert (TYPE_CODE (type) != TYPE_CODE_RANGE);
+
nfields = TYPE_NFIELDS (type);
+ TYPE_NFIELDS (new_type) = nfields;
TYPE_FIELDS (new_type) = XCALLOC (nfields, struct field);
for (i = 0; i < nfields; i++)
{
@@ -3340,8 +3543,8 @@ copy_type_recursive (struct objfile *objfile,
TYPE_FIELD_BITSIZE (new_type, i) = TYPE_FIELD_BITSIZE (type, i);
if (TYPE_FIELD_TYPE (type, i))
TYPE_FIELD_TYPE (new_type, i)
- = copy_type_recursive (objfile, TYPE_FIELD_TYPE (type, i),
- copied_types);
+ = copy_type_recursive_1 (objfile, TYPE_FIELD_TYPE (type, i),
+ copied_types);
if (TYPE_FIELD_NAME (type, i))
TYPE_FIELD_NAME (new_type, i) =
xstrdup (TYPE_FIELD_NAME (type, i));
@@ -3368,24 +3571,184 @@ copy_type_recursive (struct objfile *objfile,
}
}
+ /* Both FIELD_LOC_KIND_DWARF_BLOCK and TYPE_RANGE_HIGH_BOUND_IS_COUNT were
+ possibly converted. */
+ TYPE_DYNAMIC (new_type) = 0;
+
/* For range types, copy the bounds information. */
- if (TYPE_CODE (type) == TYPE_CODE_RANGE)
+ if (TYPE_CODE (new_type) == TYPE_CODE_RANGE)
{
TYPE_RANGE_DATA (new_type) = xmalloc (sizeof (struct range_bounds));
*TYPE_RANGE_DATA (new_type) = *TYPE_RANGE_DATA (type);
+
+ switch (TYPE_RANGE_DATA (new_type)->low.kind)
+ {
+ case RANGE_BOUND_KIND_CONSTANT:
+ break;
+ case RANGE_BOUND_KIND_DWARF_BLOCK:
+ /* `struct dwarf2_locexpr_baton' is too bound to its objfile so
+ it is expected to be made constant by CHECK_TYPEDEF.
+ TYPE_NOT_ALLOCATED and TYPE_NOT_ASSOCIATED are not valid for TYPE.
+ */
+ if (TYPE_NOT_ALLOCATED (new_type) || TYPE_NOT_ASSOCIATED (new_type)
+ || ! has_stack_frames ())
+ {
+ /* We should set 1 for Fortran but how to find the language? */
+ TYPE_LOW_BOUND (new_type) = 0;
+ TYPE_LOW_BOUND_UNDEFINED (new_type) = 1;
+ }
+ else
+ {
+ TYPE_LOW_BOUND (new_type) = dwarf_locexpr_baton_eval
+ (TYPE_RANGE_DATA (new_type)->low.u.dwarf_block);
+ if (TYPE_LOW_BOUND (new_type) >= 0)
+ TYPE_UNSIGNED (new_type) = 1;
+ }
+ TYPE_RANGE_DATA (new_type)->low.kind = RANGE_BOUND_KIND_CONSTANT;
+ break;
+ case RANGE_BOUND_KIND_DWARF_LOCLIST:
+ {
+ CORE_ADDR addr;
+
+ /* `struct dwarf2_loclist_baton' is too bound to its objfile so
+ it is expected to be made constant by CHECK_TYPEDEF.
+ TYPE_NOT_ALLOCATED and TYPE_NOT_ASSOCIATED are not valid for TYPE.
+ */
+ if (! TYPE_NOT_ALLOCATED (new_type)
+ && ! TYPE_NOT_ASSOCIATED (new_type) && has_stack_frames ()
+ && dwarf_loclist_baton_eval
+ (TYPE_RANGE_DATA (new_type)->low.u.dwarf_loclist.loclist,
+ TYPE_RANGE_DATA (new_type)->low.u.dwarf_loclist.type, &addr))
+ {
+ TYPE_LOW_BOUND (new_type) = addr;
+ if (TYPE_LOW_BOUND (new_type) >= 0)
+ TYPE_UNSIGNED (new_type) = 1;
+ }
+ else
+ {
+ /* We should set 1 for Fortran but how to find the language? */
+ TYPE_LOW_BOUND (new_type) = 0;
+ TYPE_LOW_BOUND_UNDEFINED (new_type) = 1;
+ }
+ TYPE_RANGE_DATA (new_type)->low.kind = RANGE_BOUND_KIND_CONSTANT;
+ }
+ break;
+ }
+
+ switch (TYPE_RANGE_DATA (new_type)->high.kind)
+ {
+ case RANGE_BOUND_KIND_CONSTANT:
+ break;
+ case RANGE_BOUND_KIND_DWARF_BLOCK:
+ /* `struct dwarf2_locexpr_baton' is too bound to its objfile so
+ it is expected to be made constant by CHECK_TYPEDEF.
+ TYPE_NOT_ALLOCATED and TYPE_NOT_ASSOCIATED are not valid for TYPE.
+ */
+ if (TYPE_NOT_ALLOCATED (new_type) || TYPE_NOT_ASSOCIATED (new_type)
+ || ! has_stack_frames ())
+ {
+ TYPE_HIGH_BOUND (new_type) = TYPE_LOW_BOUND (new_type) - 1;
+ TYPE_HIGH_BOUND_UNDEFINED (new_type) = 1;
+ }
+ else
+ TYPE_HIGH_BOUND (new_type) = dwarf_locexpr_baton_eval
+ (TYPE_RANGE_DATA (new_type)->high.u.dwarf_block);
+ TYPE_RANGE_DATA (new_type)->high.kind = RANGE_BOUND_KIND_CONSTANT;
+ break;
+ case RANGE_BOUND_KIND_DWARF_LOCLIST:
+ {
+ CORE_ADDR addr;
+
+ /* `struct dwarf2_loclist_baton' is too bound to its objfile so
+ it is expected to be made constant by CHECK_TYPEDEF.
+ TYPE_NOT_ALLOCATED and TYPE_NOT_ASSOCIATED are not valid for TYPE.
+ */
+ if (! TYPE_NOT_ALLOCATED (new_type)
+ && ! TYPE_NOT_ASSOCIATED (new_type) && has_stack_frames ()
+ && dwarf_loclist_baton_eval
+ (TYPE_RANGE_DATA (new_type)->high.u.dwarf_loclist.loclist,
+ TYPE_RANGE_DATA (new_type)->high.u.dwarf_loclist.type,
+ &addr))
+ TYPE_HIGH_BOUND (new_type) = addr;
+ else
+ {
+ TYPE_HIGH_BOUND (new_type) = TYPE_LOW_BOUND (new_type) - 1;
+ TYPE_HIGH_BOUND_UNDEFINED (new_type) = 1;
+ }
+ TYPE_RANGE_DATA (new_type)->high.kind = RANGE_BOUND_KIND_CONSTANT;
+ }
+ break;
+ }
+
+ switch (TYPE_RANGE_DATA (new_type)->byte_stride.kind)
+ {
+ case RANGE_BOUND_KIND_CONSTANT:
+ break;
+ case RANGE_BOUND_KIND_DWARF_BLOCK:
+ /* `struct dwarf2_locexpr_baton' is too bound to its objfile so
+ it is expected to be made constant by CHECK_TYPEDEF.
+ TYPE_NOT_ALLOCATED and TYPE_NOT_ASSOCIATED are not valid for TYPE.
+ */
+ if (TYPE_NOT_ALLOCATED (new_type) || TYPE_NOT_ASSOCIATED (new_type)
+ || ! has_stack_frames ())
+ TYPE_BYTE_STRIDE (new_type) = 0;
+ else
+ TYPE_BYTE_STRIDE (new_type) = dwarf_locexpr_baton_eval
+ (TYPE_RANGE_DATA (new_type)->byte_stride.u.dwarf_block);
+ TYPE_RANGE_DATA (new_type)->byte_stride.kind
+ = RANGE_BOUND_KIND_CONSTANT;
+ break;
+ case RANGE_BOUND_KIND_DWARF_LOCLIST:
+ {
+ CORE_ADDR addr = 0;
+
+ /* `struct dwarf2_loclist_baton' is too bound to its objfile so
+ it is expected to be made constant by CHECK_TYPEDEF.
+ TYPE_NOT_ALLOCATED and TYPE_NOT_ASSOCIATED are not valid for TYPE.
+ */
+ if (! TYPE_NOT_ALLOCATED (new_type)
+ && ! TYPE_NOT_ASSOCIATED (new_type) && has_stack_frames ())
+ dwarf_loclist_baton_eval
+ (TYPE_RANGE_DATA (new_type)->byte_stride.u.dwarf_loclist.loclist,
+ TYPE_RANGE_DATA (new_type)->byte_stride.u.dwarf_loclist.type,
+ &addr);
+ TYPE_BYTE_STRIDE (new_type) = addr;
+ TYPE_RANGE_DATA (new_type)->byte_stride.kind
+ = RANGE_BOUND_KIND_CONSTANT;
+ }
+ break;
+ }
+
+ /* Convert TYPE_RANGE_HIGH_BOUND_IS_COUNT into a regular bound. */
+ if (TYPE_RANGE_HIGH_BOUND_IS_COUNT (new_type))
+ {
+ TYPE_HIGH_BOUND (new_type) = TYPE_LOW_BOUND (new_type)
+ + TYPE_HIGH_BOUND (new_type) - 1;
+ TYPE_RANGE_HIGH_BOUND_IS_COUNT (new_type) = 0;
+ }
}
/* Copy pointers to other types. */
if (TYPE_TARGET_TYPE (type))
TYPE_TARGET_TYPE (new_type) =
- copy_type_recursive (objfile,
- TYPE_TARGET_TYPE (type),
- copied_types);
+ copy_type_recursive_1 (objfile,
+ TYPE_TARGET_TYPE (type),
+ copied_types);
if (TYPE_VPTR_BASETYPE (type))
TYPE_VPTR_BASETYPE (new_type) =
- copy_type_recursive (objfile,
- TYPE_VPTR_BASETYPE (type),
- copied_types);
+ copy_type_recursive_1 (objfile,
+ TYPE_VPTR_BASETYPE (type),
+ copied_types);
+
+ if (TYPE_CODE (new_type) == TYPE_CODE_ARRAY)
+ {
+ struct type *new_index_type = TYPE_INDEX_TYPE (new_type);
+
+ if (TYPE_BYTE_STRIDE (new_index_type) == 0)
+ TYPE_BYTE_STRIDE (new_index_type)
+ = TYPE_LENGTH (TYPE_TARGET_TYPE (new_type));
+ }
+
/* Maybe copy the type_specific bits.
NOTE drow/2005-12-09: We do not copy the C++-specific bits like
@@ -3402,6 +3765,17 @@ copy_type_recursive (struct objfile *objfile,
return new_type;
}
+/* Recursively copy (deep copy) TYPE. Return a new type allocated using
+ malloc, a saved type if we have already visited TYPE (using COPIED_TYPES),
+ or TYPE if it is not associated with OBJFILE. */
+
+struct type *
+copy_type_recursive (struct type *type,
+ htab_t copied_types)
+{
+ return copy_type_recursive_1 (TYPE_OBJFILE (type), type, copied_types);
+}
+
/* Make a copy of the given TYPE, except that the pointer & reference
types are not preserved.
@@ -3424,6 +3798,201 @@ copy_type (const struct type *type)
return new_type;
}
+#if 0
+/* Callback type for main_type_crawl. */
+typedef int (*main_type_crawl_iter) (struct type *type, void *data);
+
+/* Iterate all main_type structures reachable through any `struct type *' from
+ TYPE. ITER will be called only for one type of each main_type, use
+ TYPE_CHAIN traversal to find all the type instances. ITER is being called
+ for each main_type found. ITER returns non-zero if main_type_crawl should
+ depth-first enter the specific type. ITER must provide some detection for
+ reentering the same main_type as this function would otherwise endlessly
+ loop. */
+
+static void
+main_type_crawl (struct type *type, main_type_crawl_iter iter, void *data)
+{
+ struct type *type_iter;
+ int i;
+
+ if (!type)
+ return;
+
+ gdb_assert (TYPE_OBJFILE (type) == NULL);
+
+ /* `struct cplus_struct_type' handling is unsupported by this function. */
+ gdb_assert ((TYPE_CODE (type) != TYPE_CODE_STRUCT
+ && TYPE_CODE (type) != TYPE_CODE_UNION)
+ || !HAVE_CPLUS_STRUCT (type));
+
+ if (!(*iter) (type, data))
+ return;
+
+ /* Iterate all the type instances of this main_type. */
+ type_iter = type;
+ do
+ {
+ gdb_assert (TYPE_MAIN_TYPE (type_iter) == TYPE_MAIN_TYPE (type));
+
+ main_type_crawl (TYPE_POINTER_TYPE (type), iter, data);
+ main_type_crawl (TYPE_REFERENCE_TYPE (type), iter, data);
+
+ type_iter = TYPE_CHAIN (type_iter);
+ }
+ while (type_iter != type);
+
+ for (i = 0; i < TYPE_NFIELDS (type); i++)
+ main_type_crawl (TYPE_FIELD_TYPE (type, i), iter, data);
+
+ main_type_crawl (TYPE_TARGET_TYPE (type), iter, data);
+ main_type_crawl (TYPE_VPTR_BASETYPE (type), iter, data);
+}
+
+/* A helper for delete_type which deletes a main_type and the things to which
+ it refers. TYPE is a type whose main_type we wish to destroy. */
+
+static void
+delete_main_type (struct type *type)
+{
+ int i;
+
+ gdb_assert (TYPE_DISCARDABLE (type));
+ gdb_assert (TYPE_OBJFILE (type) == NULL);
+
+ xfree (TYPE_NAME (type));
+ xfree (TYPE_TAG_NAME (type));
+
+ for (i = 0; i < TYPE_NFIELDS (type); ++i)
+ {
+ xfree (TYPE_FIELD_NAME (type, i));
+
+ if (TYPE_FIELD_LOC_KIND (type, i) == FIELD_LOC_KIND_PHYSNAME)
+ xfree (TYPE_FIELD_STATIC_PHYSNAME (type, i));
+ }
+ xfree (TYPE_FIELDS (type));
+
+ gdb_assert (!HAVE_CPLUS_STRUCT (type));
+
+ xfree (TYPE_MAIN_TYPE (type));
+}
+
+/* Delete all the instances on TYPE_CHAIN of TYPE, including their referenced
+ main_type. TYPE must be a reclaimable type - neither permanent nor objfile
+ associated. */
+
+static void
+delete_type_chain (struct type *type)
+{
+ struct type *type_iter, *type_iter_to_free;
+
+ gdb_assert (TYPE_DISCARDABLE (type));
+ gdb_assert (TYPE_OBJFILE (type) == NULL);
+
+ delete_main_type (type);
+
+ type_iter = type;
+ do
+ {
+ type_iter_to_free = type_iter;
+ type_iter = TYPE_CHAIN (type_iter);
+ xfree (type_iter_to_free);
+ }
+ while (type_iter != type);
+}
+
+/* Hash function for type_discardable_table. */
+
+static hashval_t
+type_discardable_hash (const void *p)
+{
+ const struct type *type = p;
+
+ return htab_hash_pointer (TYPE_MAIN_TYPE (type));
+}
+
+/* Equality function for type_discardable_table. */
+
+static int
+type_discardable_equal (const void *a, const void *b)
+{
+ const struct type *left = a;
+ const struct type *right = b;
+
+ return TYPE_MAIN_TYPE (left) == TYPE_MAIN_TYPE (right);
+}
+
+/* A helper for type_mark_used. */
+
+static int
+type_mark_used_crawl (struct type *type, void *unused)
+{
+ if (!TYPE_DISCARDABLE (type))
+ return 0;
+
+ if (TYPE_DISCARDABLE_AGE (type) == type_discardable_age_current)
+ return 0;
+
+ TYPE_DISCARDABLE_AGE (type) = type_discardable_age_current;
+
+ /* Continue the traversal. */
+ return 1;
+}
+
+/* Mark TYPE and its connected types as used in this free_all_types pass. */
+
+void
+type_mark_used (struct type *type)
+{
+ if (type == NULL)
+ return;
+
+ if (!TYPE_DISCARDABLE (type))
+ return;
+
+ main_type_crawl (type, type_mark_used_crawl, NULL);
+}
+
+/* A traverse callback for type_discardable_table which removes any
+ type_discardable whose reference count is now zero (unused link). */
+
+static int
+type_discardable_remove (void **slot, void *unused)
+{
+ struct type *type = *slot;
+
+ gdb_assert (TYPE_DISCARDABLE (type));
+
+ if (TYPE_DISCARDABLE_AGE (type) != type_discardable_age_current)
+ {
+ delete_type_chain (type);
+
+ htab_clear_slot (type_discardable_table, slot);
+ }
+
+ return 1;
+}
+
+/* Free all the reclaimable types that have been allocated and that have
+ currently zero reference counter.
+
+ This function is called after each command, successful or not. Use this
+ cleanup only in the GDB idle state as GDB only marks those types used by
+ globally tracked objects (with no autovariable references tracking). */
+
+void
+free_all_types (void)
+{
+ /* Mark a new pass. As GDB checks all the entries were visited after each
+ pass there cannot be any stale entries already containing the changed
+ value. */
+ type_discardable_age_current ^= 1;
+
+ observer_notify_mark_used ();
+
+ htab_traverse (type_discardable_table, type_discardable_remove, NULL);
+}
+#endif
/* Helper functions to initialize architecture-specific types. */
@@ -3772,6 +4341,8 @@ gdbtypes_post_init (struct gdbarch *gdbarch)
= lookup_pointer_type (builtin_type->builtin_void);
builtin_type->builtin_func_ptr
= lookup_pointer_type (lookup_function_type (builtin_type->builtin_void));
+ builtin_type->builtin_func_func
+ = lookup_function_type (builtin_type->builtin_func_ptr);
/* This type represents a GDB internal function. */
builtin_type->internal_fn
@@ -3885,6 +4456,18 @@ objfile_type (struct objfile *objfile)
"<text variable, no debug info>", objfile);
TYPE_TARGET_TYPE (objfile_type->nodebug_text_symbol)
= objfile_type->builtin_int;
+ objfile_type->nodebug_text_gnu_ifunc_symbol
+ = init_type (TYPE_CODE_FUNC, 1, TYPE_FLAG_GNU_IFUNC,
+ "<text gnu-indirect-function variable, no debug info>",
+ objfile);
+ TYPE_TARGET_TYPE (objfile_type->nodebug_text_gnu_ifunc_symbol)
+ = objfile_type->nodebug_text_symbol;
+ objfile_type->nodebug_got_plt_symbol
+ = init_type (TYPE_CODE_PTR, gdbarch_addr_bit (gdbarch) / 8, 0,
+ "<text from jump slot in .got.plt, no debug info>",
+ objfile);
+ TYPE_TARGET_TYPE (objfile_type->nodebug_got_plt_symbol)
+ = objfile_type->nodebug_text_symbol;
objfile_type->nodebug_data_symbol
= init_type (TYPE_CODE_INT,
gdbarch_int_bit (gdbarch) / HOST_CHAR_BIT, 0,
@@ -3939,6 +4522,13 @@ void
_initialize_gdbtypes (void)
{
gdbtypes_data = gdbarch_data_register_post_init (gdbtypes_post_init);
+
+#if 0
+ type_discardable_table = htab_create_alloc (20, type_discardable_hash,
+ type_discardable_equal, NULL,
+ xcalloc, xfree);
+#endif
+
objfile_type_data = register_objfile_data ();
add_setshow_zinteger_cmd ("overload", no_class, &overload_debug,
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index 5f89fec..4b4720a 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -170,6 +170,7 @@ enum type_flag_value
TYPE_FLAG_VECTOR = (1 << 15),
TYPE_FLAG_FIXED_INSTANCE = (1 << 16),
TYPE_FLAG_STUB_SUPPORTED = (1 << 17),
+ TYPE_FLAG_GNU_IFUNC = (1 << 18),
/* Used for error-checking. */
TYPE_FLAG_MIN = TYPE_FLAG_UNSIGNED
@@ -214,6 +215,11 @@ enum type_instance_flag_value
#define TYPE_TARGET_STUB(t) (TYPE_MAIN_TYPE (t)->flag_target_stub)
+/* Type needs to be evaluated on each CHECK_TYPEDEF and its results must not be
+ sticky. */
+
+#define TYPE_DYNAMIC(t) (TYPE_MAIN_TYPE (t)->flag_dynamic)
+
/* Static type. If this is set, the corresponding type had
a static modifier.
Note: This may be unnecessary, since static data members
@@ -271,6 +277,12 @@ enum type_instance_flag_value
#define TYPE_NOTTEXT(t) (TYPE_INSTANCE_FLAGS (t) & TYPE_INSTANCE_FLAG_NOTTEXT)
+/* Used only for TYPE_CODE_FUNC where it specifies the real function
+ address is returned by this function call. TYPE_TARGET_TYPE determines the
+ final returned function type to be presented to user. */
+
+#define TYPE_GNU_IFUNC(t) (TYPE_MAIN_TYPE (t)->flag_gnu_ifunc)
+
/* Type owner. If TYPE_OBJFILE_OWNED is true, the type is owned by
the objfile retrieved as TYPE_OBJFILE. Otherweise, the type is
owned by an architecture; TYPE_OBJFILE is NULL in this case. */
@@ -285,6 +297,50 @@ enum type_instance_flag_value
#define TYPE_DECLARED_CLASS(t) (TYPE_MAIN_TYPE (t)->flag_declared_class)
+#if 0
+/* Define this type as being reclaimable during free_all_types. Type is
+ required to be have TYPE_OBJFILE set to NULL. Setting this flag requires
+ initializing TYPE_DISCARDABLE_AGE, see alloc_type_discardable. */
+
+#define TYPE_DISCARDABLE(t) (TYPE_MAIN_TYPE (t)->flag_discardable)
+
+/* Marker this type has been visited by the type_mark_used by this
+ mark-and-sweep types garbage collecting pass. Current pass is represented
+ by TYPE_DISCARDABLE_AGE_CURRENT. */
+
+#define TYPE_DISCARDABLE_AGE(t) (TYPE_MAIN_TYPE (t)->flag_discardable_age)
+#endif
+
+/* Is HIGH_BOUND a low-bound relative count (1) or the high bound itself (0)? */
+
+#define TYPE_RANGE_HIGH_BOUND_IS_COUNT(range_type) \
+ (TYPE_MAIN_TYPE (range_type)->flag_range_high_bound_is_count)
+
+/* Not allocated. TYPE_ALLOCATED(t) must be NULL in such case. If this flag
+ is unset and TYPE_ALLOCATED(t) is NULL then the type is allocated. If this
+ flag is unset and TYPE_ALLOCATED(t) is not NULL then its DWARF block
+ determines the actual allocation state. */
+
+#define TYPE_NOT_ALLOCATED(t) (TYPE_MAIN_TYPE (t)->flag_not_allocated)
+
+/* Not associated. TYPE_ASSOCIATED(t) must be NULL in such case. If this flag
+ is unset and TYPE_ASSOCIATED(t) is NULL then the type is associated. If
+ this flag is unset and TYPE_ASSOCIATED(t) is not NULL then its DWARF block
+ determines the actual association state. */
+
+#define TYPE_NOT_ASSOCIATED(t) (TYPE_MAIN_TYPE (t)->flag_not_associated)
+
+/* Address of the actual data as for DW_AT_data_location. Its dwarf block must
+ not be evaluated unless both TYPE_NOT_ALLOCATED and TYPE_NOT_ASSOCIATED are
+ false. If TYPE_DATA_LOCATION_IS_ADDR set then TYPE_DATA_LOCATION_ADDR value
+ is the actual data address value. If unset and
+ TYPE_DATA_LOCATION_DWARF_BLOCK is NULL then the value is the normal
+ value_raw_address. If unset and TYPE_DATA_LOCATION_DWARF_BLOCK is not NULL
+ then its DWARF block determines the actual data address. */
+
+#define TYPE_DATA_LOCATION_IS_ADDR(t) \
+ (TYPE_MAIN_TYPE (t)->flag_data_location_is_addr)
+
/* Constant type. If this is set, the corresponding type has a
const modifier. */
@@ -387,11 +443,21 @@ struct main_type
unsigned int flag_varargs : 1;
unsigned int flag_vector : 1;
unsigned int flag_stub_supported : 1;
+ unsigned int flag_gnu_ifunc : 1;
unsigned int flag_fixed_instance : 1;
unsigned int flag_objfile_owned : 1;
/* True if this type was declared with "class" rather than
"struct". */
unsigned int flag_declared_class : 1;
+#if 0
+ unsigned int flag_discardable : 1;
+ unsigned int flag_discardable_age : 1;
+#endif
+ unsigned int flag_dynamic : 1;
+ unsigned int flag_range_high_bound_is_count : 1;
+ unsigned int flag_not_allocated : 1;
+ unsigned int flag_not_associated : 1;
+ unsigned int flag_data_location_is_addr : 1;
/* A discriminant telling us which field of the type_specific union
is being used for this type, if any. */
@@ -465,6 +531,20 @@ struct main_type
struct type *target_type;
+ /* For DW_AT_data_location. */
+ union
+ {
+ struct dwarf2_locexpr_baton *dwarf_block;
+ CORE_ADDR addr;
+ }
+ data_location;
+
+ /* For DW_AT_allocated. */
+ struct dwarf2_locexpr_baton *allocated;
+
+ /* For DW_AT_associated. */
+ struct dwarf2_locexpr_baton *associated;
+
/* For structure and union types, a description of each field.
For set and pascal array types, there is one "field",
whose type is the domain type of the set or array.
@@ -539,13 +619,34 @@ struct main_type
struct range_bounds
{
+ struct
+ {
+ union
+ {
+ LONGEST constant;
+ struct dwarf2_locexpr_baton *dwarf_block;
+ struct
+ {
+ struct dwarf2_loclist_baton *loclist;
+ struct type *type;
+ }
+ dwarf_loclist;
+ }
+ u;
+ enum range_bound_kind
+ {
+ RANGE_BOUND_KIND_CONSTANT,
+ RANGE_BOUND_KIND_DWARF_BLOCK,
+ RANGE_BOUND_KIND_DWARF_LOCLIST
+ }
+ kind;
+ }
/* Low bound of range. */
-
- LONGEST low;
-
+ low,
/* High bound of range. */
-
- LONGEST high;
+ high,
+ /* Byte stride of range. */
+ byte_stride;
/* Flags indicating whether the values of low and high are
valid. When true, the respective range value is
@@ -918,9 +1019,9 @@ extern void allocate_gnat_aux_type (struct type *);
#define TYPE_POINTER_TYPE(thistype) (thistype)->pointer_type
#define TYPE_REFERENCE_TYPE(thistype) (thistype)->reference_type
#define TYPE_CHAIN(thistype) (thistype)->chain
-/* Note that if thistype is a TYPEDEF type, you have to call check_typedef.
- But check_typedef does set the TYPE_LENGTH of the TYPEDEF type,
- so you only have to call check_typedef once. Since allocate_value
+/* Note that if thistype is a TYPEDEF, ARRAY or STRING type, you have to call
+ check_typedef. But check_typedef does set the TYPE_LENGTH of the TYPEDEF
+ type, so you only have to call check_typedef once. Since allocate_value
calls check_typedef, TYPE_LENGTH (VALUE_TYPE (X)) is safe. */
#define TYPE_LENGTH(thistype) (thistype)->length
/* Note that TYPE_CODE can be TYPE_CODE_TYPEDEF, so if you want the real
@@ -928,11 +1029,16 @@ extern void allocate_gnat_aux_type (struct type *);
#define TYPE_CODE(thistype) TYPE_MAIN_TYPE(thistype)->code
#define TYPE_NFIELDS(thistype) TYPE_MAIN_TYPE(thistype)->nfields
#define TYPE_FIELDS(thistype) TYPE_MAIN_TYPE(thistype)->flds_bnds.fields
+#define TYPE_DATA_LOCATION_DWARF_BLOCK(thistype) TYPE_MAIN_TYPE (thistype)->data_location.dwarf_block
+#define TYPE_DATA_LOCATION_ADDR(thistype) TYPE_MAIN_TYPE (thistype)->data_location.addr
+#define TYPE_ALLOCATED(thistype) TYPE_MAIN_TYPE (thistype)->allocated
+#define TYPE_ASSOCIATED(thistype) TYPE_MAIN_TYPE (thistype)->associated
#define TYPE_INDEX_TYPE(type) TYPE_FIELD_TYPE (type, 0)
#define TYPE_RANGE_DATA(thistype) TYPE_MAIN_TYPE(thistype)->flds_bnds.bounds
-#define TYPE_LOW_BOUND(range_type) TYPE_RANGE_DATA(range_type)->low
-#define TYPE_HIGH_BOUND(range_type) TYPE_RANGE_DATA(range_type)->high
+#define TYPE_LOW_BOUND(range_type) TYPE_RANGE_DATA(range_type)->low.u.constant
+#define TYPE_HIGH_BOUND(range_type) TYPE_RANGE_DATA(range_type)->high.u.constant
+#define TYPE_BYTE_STRIDE(range_type) TYPE_RANGE_DATA(range_type)->byte_stride.u.constant
#define TYPE_LOW_BOUND_UNDEFINED(range_type) \
TYPE_RANGE_DATA(range_type)->low_undefined
#define TYPE_HIGH_BOUND_UNDEFINED(range_type) \
@@ -949,7 +1055,14 @@ extern void allocate_gnat_aux_type (struct type *);
(TYPE_HIGH_BOUND(TYPE_INDEX_TYPE((arraytype))))
#define TYPE_ARRAY_LOWER_BOUND_VALUE(arraytype) \
- (TYPE_LOW_BOUND(TYPE_INDEX_TYPE((arraytype))))
+ TYPE_LOW_BOUND (TYPE_INDEX_TYPE (arraytype))
+
+/* TYPE_BYTE_STRIDE (TYPE_INDEX_TYPE (arraytype)) with a fallback to the
+ element size if no specific stride value is known. */
+#define TYPE_ARRAY_BYTE_STRIDE_VALUE(arraytype) \
+ (TYPE_BYTE_STRIDE (TYPE_INDEX_TYPE (arraytype)) == 0 \
+ ? TYPE_LENGTH (TYPE_TARGET_TYPE (arraytype)) \
+ : TYPE_BYTE_STRIDE (TYPE_INDEX_TYPE (arraytype)))
/* C++ */
@@ -1178,6 +1291,10 @@ struct builtin_type
(*) () can server as a generic function pointer. */
struct type *builtin_func_ptr;
+ /* `function returning pointer to function (returning void)' type.
+ The final void return type is not significant for it. */
+ struct type *builtin_func_func;
+
/* Special-purpose types. */
@@ -1218,6 +1335,8 @@ struct objfile_type
/* Types used for symbols with no debug information. */
struct type *nodebug_text_symbol;
+ struct type *nodebug_text_gnu_ifunc_symbol;
+ struct type *nodebug_got_plt_symbol;
struct type *nodebug_data_symbol;
struct type *nodebug_unknown_symbol;
struct type *nodebug_tls_symbol;
@@ -1365,6 +1484,18 @@ extern struct type *create_array_type (struct type *, struct type *,
struct type *);
extern struct type *lookup_array_range_type (struct type *, int, int);
+extern CORE_ADDR type_range_any_field_internal (struct type *range_type,
+ int fieldno);
+
+extern int type_range_high_bound_internal (struct type *range_type);
+
+extern int type_range_count_bound_internal (struct type *range_type);
+
+extern CORE_ADDR type_range_byte_stride_internal (struct type *range_type,
+ struct type *element_type);
+
+extern void finalize_type (struct type *type);
+
extern struct type *create_string_type (struct type *, struct type *,
struct type *);
extern struct type *lookup_string_range_type (struct type *, int, int);
@@ -1410,6 +1541,10 @@ extern int is_public_ancestor (struct type *, struct type *);
extern int is_unique_ancestor (struct type *, struct value *);
+#if 0
+extern void type_mark_used (struct type *type);
+#endif
+
/* Overload resolution */
#define LENGTH_MATCH(bv) ((bv)->rank[0])
@@ -1482,10 +1617,13 @@ extern void maintenance_print_type (char *, int);
extern htab_t create_copied_types_hash (struct objfile *objfile);
-extern struct type *copy_type_recursive (struct objfile *objfile,
- struct type *type,
+extern struct type *copy_type_recursive (struct type *type,
htab_t copied_types);
extern struct type *copy_type (const struct type *type);
+#if 0
+extern void free_all_types (void);
+#endif
+
#endif /* GDBTYPES_H */
diff --git a/gdb/i386-linux-nat.c b/gdb/i386-linux-nat.c
index e32a119..2024ae8 100644
--- a/gdb/i386-linux-nat.c
+++ b/gdb/i386-linux-nat.c
@@ -649,22 +649,13 @@ i386_linux_store_inferior_registers (struct target_ops *ops,
}
-/* Support for debug registers. */
-
-static unsigned long i386_linux_dr[DR_CONTROL + 1];
-
/* Get debug register REGNUM value from only the one LWP of PTID. */
static unsigned long
-i386_linux_dr_get (ptid_t ptid, int regnum)
+i386_linux_dr_get (int tid, int regnum)
{
- int tid;
unsigned long value;
- tid = TIDGET (ptid);
- if (tid == 0)
- tid = PIDGET (ptid);
-
/* FIXME: kettenis/2001-03-27: Calling perror_with_name if the
ptrace call fails breaks debugging remote targets. The correct
way to fix this is to add the hardware breakpoint and watchpoint
@@ -686,14 +677,8 @@ i386_linux_dr_get (ptid_t ptid, int regnum)
/* Set debug register REGNUM to VALUE in only the one LWP of PTID. */
static void
-i386_linux_dr_set (ptid_t ptid, int regnum, unsigned long value)
+i386_linux_dr_set (int tid, int regnum, unsigned long value)
{
- int tid;
-
- tid = TIDGET (ptid);
- if (tid == 0)
- tid = PIDGET (ptid);
-
errno = 0;
ptrace (PTRACE_POKEUSER, tid,
offsetof (struct user, u_debugreg[regnum]), value);
@@ -701,35 +686,78 @@ i386_linux_dr_set (ptid_t ptid, int regnum, unsigned long value)
perror_with_name (_("Couldn't write debug register"));
}
-/* Set DR_CONTROL to ADDR in all LWPs of LWP_LIST. */
+/* Helper for i386_linux_dr_set_control. */
+
+static void
+i386_linux_dr_set_control_callback (int tid, void *control_voidp)
+{
+ unsigned long control = *(unsigned long *) control_voidp;
+
+ i386_linux_dr_set (tid, DR_CONTROL, control);
+}
+
+static void i386_linux_dr_set_addr (int regnum, CORE_ADDR addr);
+
+/* Set DR_CONTROL to ADDR in all LWPs of CURRENT_INFERIOR. */
static void
i386_linux_dr_set_control (unsigned long control)
{
- struct lwp_info *lp;
- ptid_t ptid;
+ int inferior_pid = ptid_get_pid (inferior_ptid);
+ struct inferior *inf = current_inferior ();
+
+ /* The amd64 counterpart and description is amd64_linux_dr_set_control. */
+ if (inf->pid != inferior_pid)
+ {
+ struct i386_dr_mirror *dr_mirror = i386_dr_mirror_get ();
+ int i;
+
+ if (!dr_mirror->addr_preset)
+ {
+ dr_mirror->addr_preset = 1;
- i386_linux_dr[DR_CONTROL] = control;
- ALL_LWPS (lp, ptid)
- i386_linux_dr_set (ptid, DR_CONTROL, control);
+ for (i = 0; i < DR_LASTADDR - DR_FIRSTADDR; i++)
+ i386_linux_dr_set_addr (i, dr_mirror->addr[i]);
+ }
+ }
+
+ linux_nat_iterate_watchpoint_lwps (i386_linux_dr_set_control_callback,
+ &control);
}
-/* Set address REGNUM (zero based) to ADDR in all LWPs of LWP_LIST. */
+/* Helper for i386_linux_dr_set_addr. */
+
+struct i386_linux_dr_set_addr_data
+ {
+ int regnum;
+ CORE_ADDR addr;
+ };
+
+static void
+i386_linux_dr_set_addr_callback (int tid, void *datap_voidp)
+{
+ const struct i386_linux_dr_set_addr_data *datap = datap_voidp;
+
+ i386_linux_dr_set (tid, DR_FIRSTADDR + datap->regnum, datap->addr);
+}
+
+/* Set address REGNUM (zero based) to ADDR in all LWPs of CURRENT_INFERIOR.
+ */
static void
i386_linux_dr_set_addr (int regnum, CORE_ADDR addr)
{
- struct lwp_info *lp;
- ptid_t ptid;
+ struct i386_linux_dr_set_addr_data data;
gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
- i386_linux_dr[DR_FIRSTADDR + regnum] = addr;
- ALL_LWPS (lp, ptid)
- i386_linux_dr_set (ptid, DR_FIRSTADDR + regnum, addr);
+ data.regnum = regnum;
+ data.addr = addr;
+ linux_nat_iterate_watchpoint_lwps (i386_linux_dr_set_addr_callback, &data);
}
-/* Set address REGNUM (zero based) to zero in all LWPs of LWP_LIST. */
+/* Set address REGNUM (zero based) to zero in all LWPs of CURRENT_INFERIOR.
+ */
static void
i386_linux_dr_reset_addr (int regnum)
@@ -742,36 +770,54 @@ i386_linux_dr_reset_addr (int regnum)
static unsigned long
i386_linux_dr_get_status (void)
{
- return i386_linux_dr_get (inferior_ptid, DR_STATUS);
+ int tid;
+
+ tid = TIDGET (inferior_ptid);
+ if (tid == 0)
+ tid = PIDGET (inferior_ptid);
+
+ return i386_linux_dr_get (tid, DR_STATUS);
}
-/* Unset MASK bits in DR_STATUS in all LWPs of LWP_LIST. */
+/* Helper for i386_linux_dr_unset_status. */
static void
-i386_linux_dr_unset_status (unsigned long mask)
+i386_linux_dr_unset_status_callback (int tid, void *mask_voidp)
{
- struct lwp_info *lp;
- ptid_t ptid;
-
- ALL_LWPS (lp, ptid)
- {
- unsigned long value;
+ unsigned long mask = *(unsigned long *) mask_voidp;
+ unsigned long value;
- value = i386_linux_dr_get (ptid, DR_STATUS);
- value &= ~mask;
- i386_linux_dr_set (ptid, DR_STATUS, value);
- }
+ value = i386_linux_dr_get (tid, DR_STATUS);
+ value &= ~mask;
+ i386_linux_dr_set (tid, DR_STATUS, value);
+}
+
+/* Unset MASK bits in DR_STATUS in all LWPs of CURRENT_INFERIOR. */
+
+static void
+i386_linux_dr_unset_status (unsigned long mask)
+{
+ linux_nat_iterate_watchpoint_lwps (i386_linux_dr_unset_status_callback,
+ &mask);
}
static void
i386_linux_new_thread (ptid_t ptid)
{
- int i;
+ struct i386_dr_mirror *dr_mirror = i386_dr_mirror_get ();
+ int i, tid;
+
+ /* Verify DR_MIRROR is valid. */
+ gdb_assert (PIDGET (ptid) == PIDGET (inferior_ptid));
+
+ tid = TIDGET (ptid);
+ if (tid == 0)
+ tid = PIDGET (ptid);
- for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
- i386_linux_dr_set (ptid, i, i386_linux_dr[i]);
+ for (i = 0; i < DR_LASTADDR - DR_FIRSTADDR; i++)
+ i386_linux_dr_set (tid, DR_FIRSTADDR + i, dr_mirror->addr[i]);
- i386_linux_dr_set (ptid, DR_CONTROL, i386_linux_dr[DR_CONTROL]);
+ i386_linux_dr_set (tid, DR_CONTROL, dr_mirror->control);
}
diff --git a/gdb/i386-nat.c b/gdb/i386-nat.c
index 7e6814e..b1e8e7d 100644
--- a/gdb/i386-nat.c
+++ b/gdb/i386-nat.c
@@ -25,6 +25,7 @@
#include "gdbcmd.h"
#include "target.h"
#include "gdb_assert.h"
+#include "inferior.h"
/* Support for hardware watchpoints and breakpoints using the i386
debug registers.
@@ -44,7 +45,6 @@ struct i386_dr_low_type i386_dr_low;
#define TARGET_HAS_DR_LEN_8 (i386_dr_low.debug_register_length == 8)
/* Debug registers' indices. */
-#define DR_NADDR 4 /* The number of debug address registers. */
#define DR_STATUS 6 /* Index of debug status register (DR6). */
#define DR_CONTROL 7 /* Index of debug control register (DR7). */
@@ -111,49 +111,60 @@ struct i386_dr_low_type i386_dr_low;
/* The I'th debug register is vacant if its Local and Global Enable
bits are reset in the Debug Control register. */
-#define I386_DR_VACANT(i) \
- ((dr_control_mirror & (3 << (DR_ENABLE_SIZE * (i)))) == 0)
+
+static inline int
+i386_dr_vacant (struct i386_dr_mirror *dr_mirror, int i)
+{
+ return (dr_mirror->control & (3 << (DR_ENABLE_SIZE * i))) == 0;
+}
/* Locally enable the break/watchpoint in the I'th debug register. */
-#define I386_DR_LOCAL_ENABLE(i) \
- dr_control_mirror |= (1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * (i)))
-/* Globally enable the break/watchpoint in the I'th debug register. */
-#define I386_DR_GLOBAL_ENABLE(i) \
- dr_control_mirror |= (1 << (DR_GLOBAL_ENABLE_SHIFT + DR_ENABLE_SIZE * (i)))
+static inline void
+i386_dr_local_enable (struct i386_dr_mirror *dr_mirror, int i)
+{
+ dr_mirror->control |= 1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * i);
+}
/* Disable the break/watchpoint in the I'th debug register. */
-#define I386_DR_DISABLE(i) \
- dr_control_mirror &= ~(3 << (DR_ENABLE_SIZE * (i)))
+
+static inline void
+i386_dr_disable (struct i386_dr_mirror *dr_mirror, int i)
+{
+ dr_mirror->control &= ~(3 << (DR_ENABLE_SIZE * i));
+}
/* Set in DR7 the RW and LEN fields for the I'th debug register. */
-#define I386_DR_SET_RW_LEN(i,rwlen) \
- do { \
- dr_control_mirror &= ~(0x0f << (DR_CONTROL_SHIFT+DR_CONTROL_SIZE*(i))); \
- dr_control_mirror |= ((rwlen) << (DR_CONTROL_SHIFT+DR_CONTROL_SIZE*(i))); \
- } while (0)
+
+static inline void
+i386_dr_set_rw_len (struct i386_dr_mirror *dr_mirror, int i, unsigned rwlen)
+{
+ dr_mirror->control &= ~(0x0f << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * i));
+ dr_mirror->control |= rwlen << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * i);
+}
/* Get from DR7 the RW and LEN fields for the I'th debug register. */
-#define I386_DR_GET_RW_LEN(i) \
- ((dr_control_mirror >> (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * (i))) & 0x0f)
+
+static inline unsigned
+i386_dr_get_rw_len (struct i386_dr_mirror *dr_mirror, int i)
+{
+ return ((dr_mirror->control >> (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * i))
+ & 0x0f);
+}
/* Mask that this I'th watchpoint has triggered. */
#define I386_DR_WATCH_MASK(i) (1 << (i))
/* Did the watchpoint whose address is in the I'th register break? */
-#define I386_DR_WATCH_HIT(i) (dr_status_mirror & I386_DR_WATCH_MASK (i))
+static inline int
+i386_dr_watch_hit (struct i386_dr_mirror *dr_mirror, int i)
+{
+ return (dr_mirror->status & I386_DR_WATCH_MASK (i)) != 0;
+}
/* A macro to loop over all debug registers. */
#define ALL_DEBUG_REGISTERS(i) for (i = 0; i < DR_NADDR; i++)
-/* Mirror the inferior's DRi registers. We keep the status and
- control registers separated because they don't hold addresses. */
-static CORE_ADDR dr_mirror[DR_NADDR];
-static unsigned long dr_status_mirror, dr_control_mirror;
-
-/* Reference counts for each debug register. */
-static int dr_ref_count[DR_NADDR];
-
/* Whether or not to print the mirrored debug registers. */
static int maint_show_dr;
@@ -195,21 +206,80 @@ static int i386_handle_nonaligned_watchpoint (i386_wp_op_t what,
/* Implementation. */
+/* Per-inferior data key. */
+static const struct inferior_data *i386_inferior_data;
+
+struct i386_inferior_data
+ {
+ /* Copy of i386 hardware debug registers for performance reasons. */
+ struct i386_dr_mirror dr_mirror;
+ };
+
+static void
+i386_inferior_data_cleanup (struct inferior *inf, void *arg)
+{
+ struct i386_inferior_data *inf_data = arg;
+
+ xfree (inf_data);
+}
+
+static struct i386_inferior_data *
+i386_inferior_data_get (void)
+{
+ struct inferior *inf = current_inferior ();
+ struct i386_inferior_data *inf_data;
+
+ inf_data = inferior_data (inf, i386_inferior_data);
+ if (inf_data == NULL)
+ {
+ inf_data = xzalloc (sizeof (*inf_data));
+ set_inferior_data (current_inferior (), i386_inferior_data, inf_data);
+ }
+
+ if (inf->pid != ptid_get_pid (inferior_ptid))
+ {
+ static struct i386_inferior_data detached_inf_data_local;
+ static int detached_inf_pid = -1;
+
+ if (detached_inf_pid != ptid_get_pid (inferior_ptid))
+ {
+ detached_inf_pid = ptid_get_pid (inferior_ptid);
+
+ /* Forked processes get a copy of the debug registers. */
+ memcpy (&detached_inf_data_local, inf_data,
+ sizeof (detached_inf_data_local));
+ detached_inf_data_local.dr_mirror.addr_preset = 0;
+ }
+
+ return &detached_inf_data_local;
+ }
+
+ return inf_data;
+}
+
/* Clear the reference counts and forget everything we knew about the
debug registers. */
+struct i386_dr_mirror *
+i386_dr_mirror_get (void)
+{
+ return &i386_inferior_data_get ()->dr_mirror;
+}
+
void
i386_cleanup_dregs (void)
{
+ struct i386_dr_mirror *dr_mirror = i386_dr_mirror_get ();
int i;
ALL_DEBUG_REGISTERS(i)
{
- dr_mirror[i] = 0;
- dr_ref_count[i] = 0;
+ dr_mirror->addr[i] = 0;
+ dr_mirror->ref_count[i] = 0;
}
- dr_control_mirror = 0;
- dr_status_mirror = 0;
+ dr_mirror->addr_preset = 0;
+ dr_mirror->control = 0;
+ dr_mirror->status = 0;
}
/* Print the values of the mirrored debug registers. This is called
@@ -220,6 +290,7 @@ static void
i386_show_dr (const char *func, CORE_ADDR addr,
int len, enum target_hw_bp_type type)
{
+ struct i386_dr_mirror *dr_mirror = i386_dr_mirror_get ();
int addr_size = gdbarch_addr_bit (target_gdbarch) / 8;
int i;
@@ -239,13 +310,16 @@ i386_show_dr (const char *func, CORE_ADDR addr,
: "??unknown??"))));
puts_unfiltered (":\n");
printf_unfiltered ("\tCONTROL (DR7): %s STATUS (DR6): %s\n",
- phex (dr_control_mirror, 8), phex (dr_status_mirror, 8));
+ phex (dr_mirror->control, 8),
+ phex (dr_mirror->status, 8));
ALL_DEBUG_REGISTERS(i)
{
printf_unfiltered ("\
\tDR%d: addr=0x%s, ref.count=%d DR%d: addr=0x%s, ref.count=%d\n",
- i, phex (dr_mirror[i], addr_size), dr_ref_count[i],
- i+1, phex (dr_mirror[i+1], addr_size), dr_ref_count[i+1]);
+ i, phex (dr_mirror->addr[i], addr_size),
+ dr_mirror->ref_count[i], i + 1,
+ phex (dr_mirror->addr[i + 1], addr_size),
+ dr_mirror->ref_count[i + 1]);
i++;
}
}
@@ -313,6 +387,7 @@ Invalid hardware breakpoint length %d in i386_length_and_rw_bits.\n"), len);
static int
i386_insert_aligned_watchpoint (CORE_ADDR addr, unsigned len_rw_bits)
{
+ struct i386_dr_mirror *dr_mirror = i386_dr_mirror_get ();
int i;
if (!i386_dr_low.set_addr || !i386_dr_low.set_control)
@@ -323,11 +398,10 @@ i386_insert_aligned_watchpoint (CORE_ADDR addr, unsigned len_rw_bits)
reuse it for this watchpoint as well (and save a register). */
ALL_DEBUG_REGISTERS(i)
{
- if (!I386_DR_VACANT (i)
- && dr_mirror[i] == addr
- && I386_DR_GET_RW_LEN (i) == len_rw_bits)
+ if (!i386_dr_vacant (dr_mirror, i) && dr_mirror->addr[i] == addr
+ && i386_dr_get_rw_len (dr_mirror, i) == len_rw_bits)
{
- dr_ref_count[i]++;
+ dr_mirror->ref_count[i]++;
return 0;
}
}
@@ -335,7 +409,7 @@ i386_insert_aligned_watchpoint (CORE_ADDR addr, unsigned len_rw_bits)
/* Next, look for a vacant debug register. */
ALL_DEBUG_REGISTERS(i)
{
- if (I386_DR_VACANT (i))
+ if (i386_dr_vacant (dr_mirror, i))
break;
}
@@ -346,9 +420,9 @@ i386_insert_aligned_watchpoint (CORE_ADDR addr, unsigned len_rw_bits)
/* Now set up the register I to watch our region. */
/* Record the info in our local mirrored array. */
- dr_mirror[i] = addr;
- dr_ref_count[i] = 1;
- I386_DR_SET_RW_LEN (i, len_rw_bits);
+ dr_mirror->addr[i] = addr;
+ dr_mirror->ref_count[i] = 1;
+ i386_dr_set_rw_len (dr_mirror, i, len_rw_bits);
/* Note: we only enable the watchpoint locally, i.e. in the current
task. Currently, no i386 target allows or supports global
watchpoints; however, if any target would want that in the
@@ -356,13 +430,13 @@ i386_insert_aligned_watchpoint (CORE_ADDR addr, unsigned len_rw_bits)
to enable watchpoints globally or locally, and the code below
should use global or local enable and slow-down flags as
appropriate. */
- I386_DR_LOCAL_ENABLE (i);
- dr_control_mirror |= DR_LOCAL_SLOWDOWN;
- dr_control_mirror &= I386_DR_CONTROL_MASK;
+ i386_dr_local_enable (dr_mirror, i);
+ dr_mirror->control |= DR_LOCAL_SLOWDOWN;
+ dr_mirror->control &= I386_DR_CONTROL_MASK;
/* Finally, actually pass the info to the inferior. */
i386_dr_low.set_addr (i, addr);
- i386_dr_low.set_control (dr_control_mirror);
+ i386_dr_low.set_control (dr_mirror->control);
/* Only a sanity check for leftover bits (set possibly only by inferior). */
if (i386_dr_low.unset_status)
@@ -380,21 +454,21 @@ i386_insert_aligned_watchpoint (CORE_ADDR addr, unsigned len_rw_bits)
static int
i386_remove_aligned_watchpoint (CORE_ADDR addr, unsigned len_rw_bits)
{
+ struct i386_dr_mirror *dr_mirror = i386_dr_mirror_get ();
int i, retval = -1;
ALL_DEBUG_REGISTERS(i)
{
- if (!I386_DR_VACANT (i)
- && dr_mirror[i] == addr
- && I386_DR_GET_RW_LEN (i) == len_rw_bits)
+ if (!i386_dr_vacant (dr_mirror, i) && dr_mirror->addr[i] == addr
+ && i386_dr_get_rw_len (dr_mirror, i) == len_rw_bits)
{
- if (--dr_ref_count[i] == 0) /* no longer in use? */
+ if (--dr_mirror->ref_count[i] == 0) /* no longer in use? */
{
/* Reset our mirror. */
- dr_mirror[i] = 0;
- I386_DR_DISABLE (i);
+ dr_mirror->addr[i] = 0;
+ i386_dr_disable (dr_mirror, i);
/* Reset it in the inferior. */
- i386_dr_low.set_control (dr_control_mirror);
+ i386_dr_low.set_control (dr_mirror->control);
if (i386_dr_low.reset_addr)
i386_dr_low.reset_addr (i);
}
@@ -556,26 +630,27 @@ i386_region_ok_for_watchpoint (CORE_ADDR addr, int len)
static int
i386_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p)
{
+ struct i386_dr_mirror *dr_mirror = i386_dr_mirror_get ();
CORE_ADDR addr = 0;
int i;
int rc = 0;
- dr_status_mirror = i386_dr_low.get_status ();
+ dr_mirror->status = i386_dr_low.get_status ();
ALL_DEBUG_REGISTERS(i)
{
- if (I386_DR_WATCH_HIT (i)
+ if (i386_dr_watch_hit (dr_mirror, i)
/* This second condition makes sure DRi is set up for a data
watchpoint, not a hardware breakpoint. The reason is
that GDB doesn't call the target_stopped_data_address
method except for data watchpoints. In other words, I'm
being paranoiac. */
- && I386_DR_GET_RW_LEN (i) != 0
+ && i386_dr_get_rw_len (dr_mirror, i) != 0
/* This third condition makes sure DRi is not vacant, this
avoids false positives in windows-nat.c. */
- && !I386_DR_VACANT (i))
+ && !i386_dr_vacant (dr_mirror, i))
{
- addr = dr_mirror[i];
+ addr = dr_mirror->addr[i];
rc = 1;
if (maint_show_dr)
i386_show_dr ("watchpoint_hit", addr, -1, hw_write);
@@ -689,6 +764,10 @@ i386_use_watchpoints (struct target_ops *t)
t->to_remove_watchpoint = i386_remove_watchpoint;
t->to_insert_hw_breakpoint = i386_insert_hw_breakpoint;
t->to_remove_hw_breakpoint = i386_remove_hw_breakpoint;
+
+ if (i386_inferior_data == NULL)
+ i386_inferior_data
+ = register_inferior_data_with_cleanup (i386_inferior_data_cleanup);
}
void
diff --git a/gdb/i386-nat.h b/gdb/i386-nat.h
index 819c6b8..bef8a35 100644
--- a/gdb/i386-nat.h
+++ b/gdb/i386-nat.h
@@ -78,6 +78,28 @@ struct i386_dr_low_type
extern struct i386_dr_low_type i386_dr_low;
+/* The number of debug address registers. */
+#define DR_NADDR 4
+
+/* Copy of hardware debug registers for performance reasons. */
+
+struct i386_dr_mirror
+ {
+ /* Mirror the inferior's DRi registers. We keep the status and
+ control registers separated because they don't hold addresses. */
+ CORE_ADDR addr[DR_NADDR];
+
+ /* All the ADDR hardware registers have been written at least once. */
+ unsigned addr_preset : 1;
+
+ /* Reference counts for each debug register. */
+ int ref_count[DR_NADDR];
+
+ unsigned long status, control;
+ };
+
+extern struct i386_dr_mirror *i386_dr_mirror_get (void);
+
/* Use this function to set i386_dr_low debug_register_length field
rather than setting it directly to check that the length is only
set once. It also enables the 'maint set/show show-debug-regs'
diff --git a/gdb/infcall.c b/gdb/infcall.c
index d42248e..ca23704 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -228,6 +228,21 @@ value_arg_coerce (struct gdbarch *gdbarch, struct value *arg,
return value_cast (type, arg);
}
+/* Return the return type of a function with its first instruction exactly at
+ the PC address. Return NULL otherwise. */
+
+static struct type *
+find_function_return_type (CORE_ADDR pc)
+{
+ struct symbol *sym = find_pc_function (pc);
+
+ if (sym != NULL && BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) == pc
+ && SYMBOL_TYPE (sym) != NULL)
+ return TYPE_TARGET_TYPE (SYMBOL_TYPE (sym));
+
+ return NULL;
+}
+
/* Determine a function's address and its return type from its value.
Calls error() if the function is not valid for calling. */
@@ -236,7 +251,6 @@ find_function_addr (struct value *function, struct type **retval_type)
{
struct type *ftype = check_typedef (value_type (function));
struct gdbarch *gdbarch = get_type_arch (ftype);
- enum type_code code = TYPE_CODE (ftype);
struct type *value_type = NULL;
CORE_ADDR funaddr;
@@ -244,24 +258,34 @@ find_function_addr (struct value *function, struct type **retval_type)
part of it. */
/* Determine address to call. */
- if (code == TYPE_CODE_FUNC || code == TYPE_CODE_METHOD)
- {
- funaddr = value_address (function);
- value_type = TYPE_TARGET_TYPE (ftype);
- }
- else if (code == TYPE_CODE_PTR)
+ if (TYPE_CODE (ftype) == TYPE_CODE_FUNC
+ || TYPE_CODE (ftype) == TYPE_CODE_METHOD)
+ funaddr = value_address (function);
+ else if (TYPE_CODE (ftype) == TYPE_CODE_PTR)
{
funaddr = value_as_address (function);
ftype = check_typedef (TYPE_TARGET_TYPE (ftype));
if (TYPE_CODE (ftype) == TYPE_CODE_FUNC
|| TYPE_CODE (ftype) == TYPE_CODE_METHOD)
+ funaddr = gdbarch_convert_from_func_ptr_addr (gdbarch, funaddr,
+ &current_target);
+ }
+ if (TYPE_CODE (ftype) == TYPE_CODE_FUNC
+ || TYPE_CODE (ftype) == TYPE_CODE_METHOD)
+ {
+ value_type = TYPE_TARGET_TYPE (ftype);
+
+ if (TYPE_GNU_IFUNC (ftype))
{
- funaddr = gdbarch_convert_from_func_ptr_addr (gdbarch, funaddr,
- &current_target);
- value_type = TYPE_TARGET_TYPE (ftype);
+ funaddr = gnu_ifunc_resolve_addr (gdbarch, funaddr);
+
+ /* Skip querying the function symbol if no RETVAL_TYPE has been
+ asked for. */
+ if (retval_type)
+ value_type = find_function_return_type (funaddr);
}
}
- else if (code == TYPE_CODE_INT)
+ else if (TYPE_CODE (ftype) == TYPE_CODE_INT)
{
/* Handle the case of functions lacking debugging info.
Their values are characters since their addresses are char. */
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 7cee7c8..751c9ef 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -54,6 +54,8 @@
#include "inline-frame.h"
#include "jit.h"
#include "tracepoint.h"
+#include "stap-probe.h"
+#include "objfiles.h"
/* Prototypes for local functions */
@@ -2247,7 +2249,7 @@ static void insert_step_resume_breakpoint_at_sal (struct gdbarch *,
struct frame_id);
static void insert_longjmp_resume_breakpoint (struct gdbarch *, CORE_ADDR);
static void check_exception_resume (struct execution_control_state *,
- struct frame_info *, struct symbol *);
+ struct frame_info *);
static void stop_stepping (struct execution_control_state *ecs);
static void prepare_to_wait (struct execution_control_state *ecs);
@@ -4164,9 +4166,17 @@ process_event_stop_test:
if (what.is_longjmp)
{
- if (!gdbarch_get_longjmp_target_p (gdbarch)
- || !gdbarch_get_longjmp_target (gdbarch,
- frame, &jmp_buf_pc))
+ struct value *arg_value;
+
+ /* If we set the longjmp breakpoint via a SystemTap probe,
+ then use it to extract the arguments. The destination
+ PC is the third argument to the probe. */
+ arg_value = stap_safe_evaluate_at_pc (frame, 2);
+ if (arg_value)
+ jmp_buf_pc = value_as_address (arg_value);
+ else if (!gdbarch_get_longjmp_target_p (gdbarch)
+ || !gdbarch_get_longjmp_target (gdbarch,
+ frame, &jmp_buf_pc))
{
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog,
@@ -4184,12 +4194,7 @@ process_event_stop_test:
insert_longjmp_resume_breakpoint (gdbarch, jmp_buf_pc);
}
else
- {
- struct symbol *func = get_frame_function (frame);
-
- if (func)
- check_exception_resume (ecs, frame, func);
- }
+ check_exception_resume (ecs, frame);
keep_going (ecs);
return;
@@ -5263,15 +5268,64 @@ insert_exception_resume_breakpoint (struct thread_info *tp,
}
}
+/* A helper for check_exception_resume that sets an
+ exception-breakpoint based on a SystemTap probe. */
+
+static void
+insert_exception_resume_from_probe (struct thread_info *tp,
+ const struct stap_probe *probe,
+ struct objfile *objfile,
+ struct frame_info *frame)
+{
+ struct value *arg_value;
+ CORE_ADDR handler;
+ struct breakpoint *bp;
+
+ arg_value = stap_safe_evaluate_at_pc (frame, 1);
+ if (!arg_value)
+ return;
+
+ handler = value_as_address (arg_value);
+
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: exception resume at %lx\n",
+ (unsigned long) handler);
+
+ bp = set_momentary_breakpoint_at_pc (get_frame_arch (frame),
+ handler, bp_exception_resume);
+ bp->thread = tp->num;
+ inferior_thread ()->control.exception_resume_breakpoint = bp;
+}
+
/* This is called when an exception has been intercepted. Check to
see whether the exception's destination is of interest, and if so,
set an exception resume breakpoint there. */
static void
check_exception_resume (struct execution_control_state *ecs,
- struct frame_info *frame, struct symbol *func)
+ struct frame_info *frame)
{
struct gdb_exception e;
+ struct objfile *objfile;
+ const struct stap_probe *probe;
+ struct symbol *func;
+
+ /* First see if this exception unwinding breakpoint was set via a
+ SystemTap probe point. If so, the probe has two arguments: the
+ CFA and the HANDLER. We ignore the CFA, extract the handler, and
+ set a breakpoint there. */
+ probe = find_probe_by_pc (get_frame_pc (frame), &objfile);
+ if (probe)
+ {
+ insert_exception_resume_from_probe (ecs->event_thread, probe,
+ objfile, frame);
+ return;
+ }
+
+ func = get_frame_function (frame);
+ if (!func)
+ return;
TRY_CATCH (e, RETURN_MASK_ERROR)
{
@@ -6253,7 +6307,8 @@ static struct lval_funcs siginfo_value_funcs =
if there's no object available. */
static struct value *
-siginfo_make_value (struct gdbarch *gdbarch, struct internalvar *var)
+siginfo_make_value (struct gdbarch *gdbarch, struct internalvar *var,
+ void *ignore)
{
if (target_has_stack
&& !ptid_equal (inferior_ptid, null_ptid)
@@ -6826,6 +6881,13 @@ show_schedule_multiple (struct ui_file *file, int from_tty,
"of all processes is %s.\n"), value);
}
+static const struct internalvar_funcs siginfo_funcs =
+{
+ siginfo_make_value,
+ NULL,
+ NULL
+};
+
void
_initialize_infrun (void)
{
@@ -7098,7 +7160,7 @@ Tells gdb whether to detach the child of a fork."),
value with a void typed value, and when we get here, gdbarch
isn't initialized yet. At this point, we're quite sure there
isn't another convenience variable of the same name. */
- create_internalvar_type_lazy ("_siginfo", siginfo_make_value);
+ create_internalvar_type_lazy ("_siginfo", &siginfo_funcs, NULL);
add_setshow_boolean_cmd ("observer", no_class,
&observer_mode_1, _("\
diff --git a/gdb/linespec.c b/gdb/linespec.c
index 3959402..24bf534 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -43,6 +43,7 @@
#include "arch-utils.h"
#include <ctype.h>
#include "cli/cli-utils.h"
+#include "stap-probe.h"
/* We share this one with symtab.c, but it is not exported widely. */
@@ -756,6 +757,7 @@ keep_name_info (char *ptr)
PC returned is 0.
FILE:FUNCTION -- likewise, but prefer functions in that file.
*EXPR -- line in which address EXPR appears.
+ probe:[OBJFILE:][PROVIDER:]NAME -- a systemtap static probe
This may all be followed by an "if EXPR", which we ignore.
@@ -823,6 +825,9 @@ decode_line_1 (char **argptr, int funfirstline, struct symtab *default_symtab,
if (**argptr == '*')
return decode_indirect (argptr);
+ if (strncmp (*argptr, "probe:", 6) == 0)
+ return parse_stap_probe (argptr);
+
is_quoted = (strchr (get_gdb_completer_quote_characters (),
**argptr) != NULL);
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index 732812d..03b3d19 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -1254,6 +1254,64 @@ iterate_over_lwps (ptid_t filter,
return NULL;
}
+/* Helper for linux_nat_iterate_watchpoint_lwps. */
+
+struct iterate_watchpoint_lwps_data
+ {
+ linux_nat_iterate_watchpoint_lwps_ftype callback;
+ void *callback_data;
+ };
+
+static int
+iterate_watchpoint_lwps_callback (struct lwp_info *lp, void *datap_voidp)
+{
+ struct iterate_watchpoint_lwps_data *datap = datap_voidp;
+ int tid;
+
+ tid = TIDGET (lp->ptid);
+ if (tid == 0)
+ tid = PIDGET (lp->ptid);
+
+ datap->callback (tid, datap->callback_data);
+
+ /* Continue the traversal. */
+ return 0;
+}
+
+/* Iterate like iterate_over_lwps does except when forking-off a child call
+ CALLBACK with CALLBACK_DATA specifically only for that new child PID.
+
+ During `set follow-fork-mode child' the call is also made for the new child
+ PID; parent watchpoints get detached elsewhere (during target_detach). */
+
+void
+linux_nat_iterate_watchpoint_lwps
+ (linux_nat_iterate_watchpoint_lwps_ftype callback, void *callback_data)
+{
+ struct iterate_watchpoint_lwps_data data;
+ int inferior_pid = ptid_get_pid (inferior_ptid);
+ struct inferior *inf = current_inferior ();
+
+ data.callback = callback;
+ data.callback_data = callback_data;
+
+ if (inf->pid == inferior_pid)
+ {
+ /* Standard mode. Iterate all the threads of the current inferior.
+ Without specifying INFERIOR_PID it would iterate all the threads of
+ all the inferiors, which is inappropriate for watchpoints. */
+
+ iterate_over_lwps (pid_to_ptid (inferior_pid),
+ iterate_watchpoint_lwps_callback, &data);
+ }
+ else
+ {
+ /* Detaching a new child PID temporarily present in INFERIOR_PID. */
+
+ callback (inferior_pid, callback_data);
+ }
+}
+
/* Update our internal state when changing from one checkpoint to
another indicated by NEW_PTID. We can only switch single-threaded
applications, so we only create one new LWP, and the previous list
diff --git a/gdb/linux-nat.h b/gdb/linux-nat.h
index 42cb2fc..05ac11d 100644
--- a/gdb/linux-nat.h
+++ b/gdb/linux-nat.h
@@ -140,6 +140,11 @@ struct lwp_info *iterate_over_lwps (ptid_t filter,
void *),
void *data);
+typedef void (*linux_nat_iterate_watchpoint_lwps_ftype) (int tid, void *data);
+
+extern void linux_nat_iterate_watchpoint_lwps
+ (linux_nat_iterate_watchpoint_lwps_ftype callback, void *callback_data);
+
/* Create a prototype generic GNU/Linux target. The client can
override it with local methods. */
struct target_ops * linux_target (void);
diff --git a/gdb/machoread.c b/gdb/machoread.c
index dbf9ae4..3db9e16 100644
--- a/gdb/machoread.c
+++ b/gdb/machoread.c
@@ -849,6 +849,7 @@ static const struct sym_fns macho_sym_fns = {
default_symfile_segments, /* Get segment information from a file. */
NULL,
macho_symfile_relocate, /* Relocate a debug section. */
+ NULL, /* sym_get_probes */
&psym_functions
};
diff --git a/gdb/main.c b/gdb/main.c
index ff305a1..267f0b0 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -39,6 +39,7 @@
#include "interps.h"
#include "main.h"
+#include "python/python.h"
#include "source.h"
#include "cli/cli-cmds.h"
#include "python/python.h"
@@ -260,6 +261,8 @@ captured_main (void *data)
char *cdarg = NULL;
char *ttyarg = NULL;
+ int python_script = 0;
+
/* These are static so that we can take their address in an
initializer. */
static int print_help;
@@ -451,10 +454,14 @@ captured_main (void *data)
{"args", no_argument, &set_args, 1},
{"l", required_argument, 0, 'l'},
{"return-child-result", no_argument, &return_child_result, 1},
+#if HAVE_PYTHON
+ {"python", no_argument, 0, 'P'},
+ {"P", no_argument, 0, 'P'},
+#endif
{0, no_argument, 0, 0}
};
- while (1)
+ while (!python_script)
{
int option_index;
@@ -472,6 +479,9 @@ captured_main (void *data)
case 0:
/* Long option that just sets a flag. */
break;
+ case 'P':
+ python_script = 1;
+ break;
case OPT_SE:
symarg = optarg;
execarg = optarg;
@@ -667,7 +677,31 @@ captured_main (void *data)
/* Now that gdb_init has created the initial inferior, we're in
position to set args for that inferior. */
- if (set_args)
+ if (python_script)
+ {
+ /* The first argument is a python script to evaluate, and
+ subsequent arguments are passed to the script for
+ processing there. */
+ if (optind >= argc)
+ {
+ fprintf_unfiltered (gdb_stderr,
+ _("%s: Python script file name required\n"),
+ argv[0]);
+ exit (1);
+ }
+
+ /* FIXME: should handle inferior I/O intelligently here.
+ E.g., should be possible to run gdb in pipeline and have
+ Python (and gdb) output go to stderr or file; and if a
+ prompt is needed, open the tty. */
+ quiet = 1;
+ /* FIXME: should read .gdbinit if, and only if, a prompt is
+ requested by the script. Though... maybe this is not
+ ideal? */
+ /* FIXME: likewise, reading in history. */
+ inhibit_gdbinit = 1;
+ }
+ else if (set_args)
{
/* The remaining options are the command-line options for the
inferior. The first one is the sym/exec file, and the rest
@@ -916,7 +950,8 @@ captured_main (void *data)
/* Read in the old history after all the command files have been
read. */
- init_history ();
+ if (!python_script)
+ init_history ();
if (batch_flag)
{
@@ -927,13 +962,25 @@ captured_main (void *data)
/* Show time and/or space usage. */
do_cleanups (pre_stat_chain);
- /* NOTE: cagney/1999-11-07: There is probably no reason for not
- moving this loop and the code found in captured_command_loop()
- into the command_loop() proper. The main thing holding back that
- change - SET_TOP_LEVEL() - has been eliminated. */
- while (1)
+#if HAVE_PYTHON
+ if (python_script)
{
- catch_errors (captured_command_loop, 0, "", RETURN_MASK_ALL);
+ extern int pagination_enabled;
+ pagination_enabled = 0;
+ run_python_script (argc - optind, &argv[optind]);
+ return 1;
+ }
+ else
+#endif
+ {
+ /* NOTE: cagney/1999-11-07: There is probably no reason for not
+ moving this loop and the code found in captured_command_loop()
+ into the command_loop() proper. The main thing holding back that
+ change - SET_TOP_LEVEL() - has been eliminated. */
+ while (1)
+ {
+ catch_errors (captured_command_loop, 0, "", RETURN_MASK_ALL);
+ }
}
/* No exit -- exit is through quit_command. */
}
@@ -965,7 +1012,12 @@ print_gdb_help (struct ui_file *stream)
fputs_unfiltered (_("\
This is the GNU debugger. Usage:\n\n\
gdb [options] [executable-file [core-file or process-id]]\n\
- gdb [options] --args executable-file [inferior-arguments ...]\n\n\
+ gdb [options] --args executable-file [inferior-arguments ...]\n"), stream);
+#if HAVE_PYTHON
+ fputs_unfiltered (_("\
+ gdb [options] [--python|-P] script-file [script-arguments ...]\n"), stream);
+#endif
+ fputs_unfiltered (_("\n\
Options:\n\n\
"), stream);
fputs_unfiltered (_("\
@@ -1003,7 +1055,13 @@ Options:\n\n\
--nw Do not use a window interface.\n\
--nx Do not read "), stream);
fputs_unfiltered (gdbinit, stream);
- fputs_unfiltered (_(" file.\n\
+ fputs_unfiltered (_(" file.\n"), stream);
+#if HAVE_PYTHON
+ fputs_unfiltered (_("\
+ --python, -P Following argument is Python script file; remaining\n\
+ arguments are passed to script.\n"), stream);
+#endif
+ fputs_unfiltered (_("\
--quiet Do not print version number on startup.\n\
--readnow Fully read symbol files on first access.\n\
"), stream);
diff --git a/gdb/mi/mi-cmd-var.c b/gdb/mi/mi-cmd-var.c
index a401846..26dca8c 100644
--- a/gdb/mi/mi-cmd-var.c
+++ b/gdb/mi/mi-cmd-var.c
@@ -707,7 +707,6 @@ mi_cmd_var_update (char *command, char **argv, int argc)
}
else
{
- /* Get varobj handle, if a valid var obj name was specified */
struct varobj *var = varobj_get_handle (name);
varobj_update_one (var, print_values, 1 /* explicit */);
diff --git a/gdb/minsyms.c b/gdb/minsyms.c
index 4ae7f27..97d425e 100644
--- a/gdb/minsyms.c
+++ b/gdb/minsyms.c
@@ -333,8 +333,9 @@ lookup_minimal_symbol_text (const char *name, struct objfile *objf)
msymbol = msymbol->hash_next)
{
if (strcmp (SYMBOL_LINKAGE_NAME (msymbol), name) == 0 &&
- (MSYMBOL_TYPE (msymbol) == mst_text ||
- MSYMBOL_TYPE (msymbol) == mst_file_text))
+ (MSYMBOL_TYPE (msymbol) == mst_text
+ || MSYMBOL_TYPE (msymbol) == mst_text_gnu_ifunc
+ || MSYMBOL_TYPE (msymbol) == mst_file_text))
{
switch (MSYMBOL_TYPE (msymbol))
{
@@ -696,6 +697,69 @@ lookup_minimal_symbol_by_pc (CORE_ADDR pc)
return lookup_minimal_symbol_by_pc_section (pc, NULL);
}
+/* Return non-zero iff PC is in an STT_GNU_IFUNC function resolver. */
+
+int
+in_gnu_ifunc_stub (CORE_ADDR pc)
+{
+ struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (pc);
+
+ return msymbol && MSYMBOL_TYPE (msymbol) == mst_text_gnu_ifunc;
+}
+
+/* See elf_gnu_ifunc_resolve_addr for its real implementation. */
+
+static CORE_ADDR
+stub_gnu_ifunc_resolve_addr (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ error (_("GDB cannot resolve STT_GNU_IFUNC symbol at address %s without "
+ "the ELF support compiled in."),
+ paddress (gdbarch, pc));
+}
+
+/* See elf_gnu_ifunc_resolve_name for its real implementation. */
+
+static int
+stub_gnu_ifunc_resolve_name (const char *function_name,
+ CORE_ADDR *function_address_p)
+{
+ error (_("GDB cannot resolve STT_GNU_IFUNC symbol \"%s\" without "
+ "the ELF support compiled in."),
+ function_name);
+}
+
+/* See elf_gnu_ifunc_resolver_stop for its real implementation. */
+
+static void
+stub_gnu_ifunc_resolver_stop (struct breakpoint *b)
+{
+ internal_error (__FILE__, __LINE__,
+ _("elf_gnu_ifunc_resolver_stop cannot be reached."));
+}
+
+/* See elf_gnu_ifunc_resolver_return_stop for its real implementation. */
+
+static void
+stub_gnu_ifunc_resolver_return_stop (struct breakpoint *b)
+{
+ internal_error (__FILE__, __LINE__,
+ _("elf_gnu_ifunc_resolver_return_stop cannot be reached."));
+}
+
+/* See elf_gnu_ifunc_fns for its real implementation. */
+
+static const struct gnu_ifunc_fns stub_gnu_ifunc_fns =
+{
+ stub_gnu_ifunc_resolve_addr,
+ stub_gnu_ifunc_resolve_name,
+ stub_gnu_ifunc_resolver_stop,
+ stub_gnu_ifunc_resolver_return_stop,
+};
+
+/* A placeholder for &elf_gnu_ifunc_fns. */
+
+const struct gnu_ifunc_fns *gnu_ifunc_fns_p = &stub_gnu_ifunc_fns;
+
/* Find the minimal symbol named NAME, and return both the minsym
struct and its objfile. This only checks the linkage name. Sets
*OBJFILE_P and returns the minimal symbol, if it is found. If it
@@ -765,6 +829,7 @@ prim_record_minimal_symbol (const char *name, CORE_ADDR address,
switch (ms_type)
{
case mst_text:
+ case mst_text_gnu_ifunc:
case mst_file_text:
case mst_solib_trampoline:
section = SECT_OFF_TEXT (objfile);
@@ -1230,7 +1295,8 @@ find_solib_trampoline_target (struct frame_info *frame, CORE_ADDR pc)
{
ALL_MSYMBOLS (objfile, msymbol)
{
- if (MSYMBOL_TYPE (msymbol) == mst_text
+ if ((MSYMBOL_TYPE (msymbol) == mst_text
+ || MSYMBOL_TYPE (msymbol) == mst_text_gnu_ifunc)
&& strcmp (SYMBOL_LINKAGE_NAME (msymbol),
SYMBOL_LINKAGE_NAME (tsymbol)) == 0)
return SYMBOL_VALUE_ADDRESS (msymbol);
diff --git a/gdb/mipsread.c b/gdb/mipsread.c
index 74d795d..7e05317 100644
--- a/gdb/mipsread.c
+++ b/gdb/mipsread.c
@@ -402,6 +402,7 @@ static const struct sym_fns ecoff_sym_fns =
default_symfile_segments, /* Get segment information from a file. */
NULL,
default_symfile_relocate, /* Relocate a debug section. */
+ NULL, /* sym_probe_fns */
&psym_functions
};
diff --git a/gdb/objfiles.c b/gdb/objfiles.c
index f3259dd..1309cdb 100644
--- a/gdb/objfiles.c
+++ b/gdb/objfiles.c
@@ -846,6 +846,11 @@ objfile_relocate1 (struct objfile *objfile,
obj_section_addr (s));
}
+ /* Relocating Systemtap probes. */
+ if (objfile->sf && objfile->sf->sym_probe_fns)
+ objfile->sf->sym_probe_fns->sym_relocate_probe (objfile,
+ new_offsets, delta);
+
/* Data changed. */
return 1;
}
diff --git a/gdb/p-valprint.c b/gdb/p-valprint.c
index d2efa5b..d98b3a4 100644
--- a/gdb/p-valprint.c
+++ b/gdb/p-valprint.c
@@ -39,6 +39,7 @@
#include "cp-abi.h"
#include "cp-support.h"
#include "exceptions.h"
+#include "dwarf2loc.h"
/* See val_print for a description of the various parameters of this
@@ -63,8 +64,31 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr,
struct type *char_type;
LONGEST val;
CORE_ADDR addr;
+ struct cleanup *back_to;
+ struct type *saved_type = type;
+ CORE_ADDR saved_address = address;
+
+ back_to = make_cleanup (null_cleanup, 0);
+ address += embedded_offset;
+ type = object_address_get_data (type, &address);
+ if (type == NULL)
+ {
+ fputs_filtered (object_address_data_not_valid (saved_type), stream);
+ gdb_flush (stream);
+ do_cleanups (back_to);
+ return 0;
+ }
+ if (address != saved_address + embedded_offset)
+ {
+ size_t length = TYPE_LENGTH (type);
- CHECK_TYPEDEF (type);
+ valaddr = xmalloc (length);
+ make_cleanup (xfree, (gdb_byte *) valaddr);
+ read_memory (address, (gdb_byte *) valaddr, length);
+ embedded_offset = 0;
+ }
+ else
+ address -= embedded_offset;
switch (TYPE_CODE (type))
{
case TYPE_CODE_ARRAY:
@@ -120,8 +144,8 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr,
{
i = 0;
}
- val_print_array_elements (type, valaddr, embedded_offset,
- address, stream, recurse,
+ val_print_array_elements (saved_type, valaddr, embedded_offset,
+ saved_address, stream, recurse,
original_value, options, i);
fprintf_filtered (stream, "}");
}
@@ -160,6 +184,7 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr,
/* Try to print what function it points to. */
print_address_demangle (gdbarch, addr, stream, demangle);
/* Return value is irrelevant except for string pointers. */
+ do_cleanups (back_to);
return (0);
}
@@ -251,6 +276,7 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr,
/* Return number of characters printed, including the terminating
'\0' if we reached the end. val_print_string takes care including
the terminating '\0' if necessary. */
+ do_cleanups (back_to);
return i;
break;
@@ -567,6 +593,7 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr,
TYPE_CODE (type));
}
gdb_flush (stream);
+ do_cleanups (back_to);
return (0);
}
diff --git a/gdb/parse.c b/gdb/parse.c
index 02a7d89..81f3f0c 100644
--- a/gdb/parse.c
+++ b/gdb/parse.c
@@ -487,9 +487,22 @@ write_exp_msymbol (struct minimal_symbol *msymbol)
pc = gdbarch_convert_from_func_ptr_addr (gdbarch, addr, &current_target);
if (pc != addr)
{
+ struct minimal_symbol *ifunc_msym = lookup_minimal_symbol_by_pc (pc);
+
/* In this case, assume we have a code symbol instead of
a data symbol. */
- type = mst_text;
+
+ if (ifunc_msym != NULL && MSYMBOL_TYPE (ifunc_msym) == mst_text_gnu_ifunc
+ && SYMBOL_VALUE_ADDRESS (ifunc_msym) == pc)
+ {
+ /* A function descriptor has been resolved but PC is still in the
+ STT_GNU_IFUNC resolver body (such as because inferior does not
+ run to be able to call it). */
+
+ type = mst_text_gnu_ifunc;
+ }
+ else
+ type = mst_text;
section = NULL;
addr = pc;
}
@@ -521,6 +534,11 @@ write_exp_msymbol (struct minimal_symbol *msymbol)
write_exp_elt_type (objfile_type (objfile)->nodebug_text_symbol);
break;
+ case mst_text_gnu_ifunc:
+ write_exp_elt_type (objfile_type (objfile)
+ ->nodebug_text_gnu_ifunc_symbol);
+ break;
+
case mst_data:
case mst_file_data:
case mst_bss:
@@ -528,6 +546,10 @@ write_exp_msymbol (struct minimal_symbol *msymbol)
write_exp_elt_type (objfile_type (objfile)->nodebug_data_symbol);
break;
+ case mst_slot_got_plt:
+ write_exp_elt_type (objfile_type (objfile)->nodebug_got_plt_symbol);
+ break;
+
default:
write_exp_elt_type (objfile_type (objfile)->nodebug_unknown_symbol);
break;
@@ -1480,6 +1502,7 @@ parser_fprintf (FILE *x, const char *y, ...)
int
operator_check_standard (struct expression *exp, int pos,
+ int (*type_func) (struct type *type, void *data),
int (*objfile_func) (struct objfile *objfile,
void *data),
void *data)
@@ -1521,7 +1544,7 @@ operator_check_standard (struct expression *exp, int pos,
struct type *type = elts[pos + 2 + arg].type;
struct objfile *objfile = TYPE_OBJFILE (type);
- if (objfile && (*objfile_func) (objfile, data))
+ if (objfile && objfile_func && (*objfile_func) (objfile, data))
return 1;
}
}
@@ -1539,7 +1562,8 @@ operator_check_standard (struct expression *exp, int pos,
/* Check objfile where the variable itself is placed.
SYMBOL_OBJ_SECTION (symbol) may be NULL. */
- if ((*objfile_func) (SYMBOL_SYMTAB (symbol)->objfile, data))
+ if (objfile_func
+ && (*objfile_func) (SYMBOL_SYMTAB (symbol)->objfile, data))
return 1;
/* Check objfile where is placed the code touching the variable. */
@@ -1552,24 +1576,27 @@ operator_check_standard (struct expression *exp, int pos,
/* Invoke callbacks for TYPE and OBJFILE if they were set as non-NULL. */
- if (type && TYPE_OBJFILE (type)
+ if (type && type_func && (*type_func) (type, data))
+ return 1;
+ if (type && TYPE_OBJFILE (type) && objfile_func
&& (*objfile_func) (TYPE_OBJFILE (type), data))
return 1;
- if (objfile && (*objfile_func) (objfile, data))
+ if (objfile && objfile_func && (*objfile_func) (objfile, data))
return 1;
return 0;
}
-/* Call OBJFILE_FUNC for any TYPE and OBJFILE found being referenced by EXP.
- The functions are never called with NULL OBJFILE. Functions get passed an
- arbitrary caller supplied DATA pointer. If any of the functions returns
- non-zero value then (any other) non-zero value is immediately returned to
- the caller. Otherwise zero is returned after iterating through whole EXP.
- */
+/* Call TYPE_FUNC and OBJFILE_FUNC for any TYPE and OBJFILE found being
+ referenced by EXP. The functions are never called with NULL TYPE or NULL
+ OBJFILE. Functions get passed an arbitrary caller supplied DATA pointer.
+ If any of the functions returns non-zero value then (any other) non-zero
+ value is immediately returned to the caller. Otherwise zero is returned
+ after iterating through whole EXP. */
static int
exp_iterate (struct expression *exp,
+ int (*type_func) (struct type *type, void *data),
int (*objfile_func) (struct objfile *objfile, void *data),
void *data)
{
@@ -1584,7 +1611,9 @@ exp_iterate (struct expression *exp,
pos = endpos - oplen;
if (exp->language_defn->la_exp_desc->operator_check (exp, pos,
- objfile_func, data))
+ type_func,
+ objfile_func,
+ data))
return 1;
endpos = pos;
@@ -1615,8 +1644,29 @@ exp_uses_objfile (struct expression *exp, struct objfile *objfile)
{
gdb_assert (objfile->separate_debug_objfile_backlink == NULL);
- return exp_iterate (exp, exp_uses_objfile_iter, objfile);
+ return exp_iterate (exp, NULL, exp_uses_objfile_iter, objfile);
+}
+
+/* Helper for exp_types_mark_used. */
+
+#if 0
+static int
+exp_types_mark_used_iter (struct type *type, void *unused)
+{
+ type_mark_used (type);
+
+ /* Continue the traversal. */
+ return 0;
+}
+
+/* Call type_mark_used for any type contained in EXP. */
+
+void
+exp_types_mark_used (struct expression *exp)
+{
+ exp_iterate (exp, exp_types_mark_used_iter, NULL, NULL);
}
+#endif
void
_initialize_parse (void)
diff --git a/gdb/parser-defs.h b/gdb/parser-defs.h
index 3f743d1..3b942c4 100644
--- a/gdb/parser-defs.h
+++ b/gdb/parser-defs.h
@@ -194,6 +194,8 @@ extern void operator_length_standard (const struct expression *, int, int *,
int *);
extern int operator_check_standard (struct expression *exp, int pos,
+ int (*type_func) (struct type *type,
+ void *data),
int (*objfile_func)
(struct objfile *objfile, void *data),
void *data);
@@ -291,6 +293,7 @@ struct exp_descriptor
value should be immediately returned to the caller. Otherwise zero
should be returned. */
int (*operator_check) (struct expression *exp, int pos,
+ int (*type_func) (struct type *type, void *data),
int (*objfile_func) (struct objfile *objfile,
void *data),
void *data);
@@ -329,4 +332,10 @@ extern void parser_fprintf (FILE *, const char *, ...) ATTRIBUTE_PRINTF (2, 3);
extern int exp_uses_objfile (struct expression *exp, struct objfile *objfile);
+extern int exp_uses_objfile (struct expression *exp, struct objfile *objfile);
+
+#if 0
+extern void exp_types_mark_used (struct expression *exp);
+#endif
+
#endif /* PARSER_DEFS_H */
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
index 049cde8..f3d35ec 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -1637,12 +1637,18 @@ booke_remove_point (struct ppc_hw_breakpoint *b, int tid)
hw_breaks[i].hw_break = NULL;
}
+static void
+booke_insert_point_callback (int tid, void *pp_voidp)
+{
+ struct ppc_hw_breakpoint *pp = pp_voidp;
+
+ booke_insert_point (pp, tid);
+}
+
static int
ppc_linux_insert_hw_breakpoint (struct gdbarch *gdbarch,
struct bp_target_info *bp_tgt)
{
- ptid_t ptid;
- struct lwp_info *lp;
struct ppc_hw_breakpoint p;
if (!have_ptrace_booke_interface ())
@@ -1656,18 +1662,23 @@ ppc_linux_insert_hw_breakpoint (struct gdbarch *gdbarch,
p.addr2 = 0;
p.condition_value = 0;
- ALL_LWPS (lp, ptid)
- booke_insert_point (&p, TIDGET (ptid));
+ linux_nat_iterate_watchpoint_lwps (booke_insert_point_callback, &p);
return 0;
}
+static void
+booke_remove_point_callback (int tid, void *pp_voidp)
+{
+ struct ppc_hw_breakpoint *pp = pp_voidp;
+
+ booke_remove_point (pp, tid);
+}
+
static int
ppc_linux_remove_hw_breakpoint (struct gdbarch *gdbarch,
struct bp_target_info *bp_tgt)
{
- ptid_t ptid;
- struct lwp_info *lp;
struct ppc_hw_breakpoint p;
if (!have_ptrace_booke_interface ())
@@ -1681,8 +1692,7 @@ ppc_linux_remove_hw_breakpoint (struct gdbarch *gdbarch,
p.addr2 = 0;
p.condition_value = 0;
- ALL_LWPS (lp, ptid)
- booke_remove_point (&p, TIDGET (ptid));
+ linux_nat_iterate_watchpoint_lwps (booke_remove_point_callback, &p);
return 0;
}
@@ -1896,6 +1906,15 @@ ppc_linux_can_accel_watchpoint_condition (CORE_ADDR addr, int len, int rw,
&& check_condition (addr, cond, &data_value));
}
+static void
+set_saved_dabr_value_callback (int tid, void *retp_voidp)
+{
+ int *retp = retp_voidp;
+
+ if (ptrace (PTRACE_SET_DEBUGREG, tid, 0, saved_dabr_value) < 0)
+ *retp = -1;
+}
+
/* Set up P with the parameters necessary to request a watchpoint covering
LEN bytes starting at ADDR and if possible with condition expression COND
evaluated by hardware. INSERT tells if we are creating a request for
@@ -1949,8 +1968,6 @@ static int
ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw,
struct expression *cond)
{
- struct lwp_info *lp;
- ptid_t ptid;
int ret = -1;
if (have_ptrace_booke_interface ())
@@ -1959,8 +1976,7 @@ ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw,
create_watchpoint_request (&p, addr, len, rw, cond, 1);
- ALL_LWPS (lp, ptid)
- booke_insert_point (&p, TIDGET (ptid));
+ linux_nat_iterate_watchpoint_lwps (booke_insert_point_callback, &p);
ret = 0;
}
@@ -2003,12 +2019,8 @@ ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw,
saved_dabr_value = dabr_value;
- ALL_LWPS (lp, ptid)
- if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0,
- saved_dabr_value) < 0)
- return -1;
-
ret = 0;
+ linux_nat_iterate_watchpoint_lwps (set_saved_dabr_value_callback, &ret);
}
return ret;
@@ -2018,8 +2030,6 @@ static int
ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw,
struct expression *cond)
{
- struct lwp_info *lp;
- ptid_t ptid;
int ret = -1;
if (have_ptrace_booke_interface ())
@@ -2028,20 +2038,16 @@ ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw,
create_watchpoint_request (&p, addr, len, rw, cond, 0);
- ALL_LWPS (lp, ptid)
- booke_remove_point (&p, TIDGET (ptid));
+ linux_nat_iterate_watchpoint_lwps (booke_remove_point_callback, &p);
ret = 0;
}
else
{
saved_dabr_value = 0;
- ALL_LWPS (lp, ptid)
- if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0,
- saved_dabr_value) < 0)
- return -1;
ret = 0;
+ linux_nat_iterate_watchpoint_lwps (set_saved_dabr_value_callback, &ret);
}
return ret;
diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index 81360ad..8fa9a99 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -977,6 +977,11 @@ print_command_1 (char *exp, int inspect, int voidprint)
else
val = access_value_history (0);
+ /* Do not try to OBJECT_ADDRESS_SET here anything. We are interested in the
+ source variable base addresses as found by READ_VAR_VALUE. The value here
+ can be already a calculated expression address inappropriate for
+ DW_OP_push_object_address. */
+
if (voidprint || (val && value_type (val) &&
TYPE_CODE (value_type (val)) != TYPE_CODE_VOID))
{
@@ -1478,6 +1483,24 @@ x_command (char *exp, int from_tty)
set_internalvar (lookup_internalvar ("__"), last_examine_value);
}
}
+
+#if 0
+/* Call type_mark_used for any TYPEs referenced from this GDB source file. */
+
+static void
+print_types_mark_used (void)
+{
+ struct display *d;
+
+ if (last_examine_value)
+ type_mark_used (value_type (last_examine_value));
+
+ for (d = display_chain; d; d = d->next)
+ if (d->exp)
+ exp_types_mark_used (d->exp);
+}
+#endif
+
/* Add an expression to the auto-display chain.
@@ -2872,4 +2895,8 @@ Show printing of source filename and line number with <symbol>."), NULL,
add_com ("eval", no_class, eval_command, _("\
Convert \"printf format string\", arg1, arg2, arg3, ..., argn to\n\
a command line, and call it."));
+
+#if 0
+ observer_attach_mark_used (print_types_mark_used);
+#endif
}
diff --git a/gdb/python/lib/gdb/FrameIterator.py b/gdb/python/lib/gdb/FrameIterator.py
new file mode 100644
index 0000000..5654546
--- /dev/null
+++ b/gdb/python/lib/gdb/FrameIterator.py
@@ -0,0 +1,33 @@
+# Iterator over frames.
+
+# Copyright (C) 2008, 2009 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 <http://www.gnu.org/licenses/>.
+
+class FrameIterator:
+ """An iterator that iterates over frames."""
+
+ def __init__ (self, frame):
+ "Initialize a FrameIterator. FRAME is the starting frame."
+ self.frame = frame
+
+ def __iter__ (self):
+ return self
+
+ def next (self):
+ result = self.frame
+ if result is None:
+ raise StopIteration
+ self.frame = result.older ()
+ return result
diff --git a/gdb/python/lib/gdb/FrameWrapper.py b/gdb/python/lib/gdb/FrameWrapper.py
new file mode 100644
index 0000000..b790a54
--- /dev/null
+++ b/gdb/python/lib/gdb/FrameWrapper.py
@@ -0,0 +1,112 @@
+# Wrapper API for frames.
+
+# Copyright (C) 2008, 2009 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 <http://www.gnu.org/licenses/>.
+
+import gdb
+
+# FIXME: arguably all this should be on Frame somehow.
+class FrameWrapper:
+ def __init__ (self, frame):
+ self.frame = frame;
+
+ def write_symbol (self, stream, sym, block):
+ if len (sym.linkage_name):
+ nsym, is_field_of_this = gdb.lookup_symbol (sym.linkage_name, block)
+ if nsym.addr_class != gdb.SYMBOL_LOC_REGISTER:
+ sym = nsym
+
+ stream.write (sym.print_name + "=")
+ try:
+ val = self.read_var (sym)
+ if val != None:
+ val = str (val)
+ # FIXME: would be nice to have a more precise exception here.
+ except RuntimeError, text:
+ val = text
+ if val == None:
+ stream.write ("???")
+ else:
+ stream.write (str (val))
+
+ def print_frame_locals (self, stream, func):
+ if not func:
+ return
+
+ first = True
+ block = func.value
+
+ for sym in block:
+ if sym.is_argument:
+ continue;
+
+ self.write_symbol (stream, sym, block)
+ stream.write ('\n')
+
+ def print_frame_args (self, stream, func):
+ if not func:
+ return
+
+ first = True
+ block = func.value
+
+ for sym in block:
+ if not sym.is_argument:
+ continue;
+
+ if not first:
+ stream.write (", ")
+
+ self.write_symbol (stream, sym, block)
+ first = False
+
+ # FIXME: this should probably just be a method on gdb.Frame.
+ # But then we need stream wrappers.
+ def describe (self, stream, full):
+ if self.type () == gdb.DUMMY_FRAME:
+ stream.write (" <function called from gdb>\n")
+ elif self.type () == gdb.SIGTRAMP_FRAME:
+ stream.write (" <signal handler called>\n")
+ else:
+ sal = self.find_sal ()
+ pc = self.pc ()
+ name = self.name ()
+ if not name:
+ name = "??"
+ if pc != sal.pc or not sal.symtab:
+ stream.write (" 0x%08x in" % pc)
+ stream.write (" " + name + " (")
+
+ func = self.function ()
+ self.print_frame_args (stream, func)
+
+ stream.write (")")
+
+ if sal.symtab and sal.symtab.filename:
+ stream.write (" at " + sal.symtab.filename)
+ stream.write (":" + str (sal.line))
+
+ if not self.name () or (not sal.symtab or not sal.symtab.filename):
+ lib = gdb.solib_address (pc)
+ if lib:
+ stream.write (" from " + lib)
+
+ stream.write ("\n")
+
+ if full:
+ self.print_frame_locals (stream, func)
+
+ def __getattr__ (self, name):
+ return getattr (self.frame, name)
diff --git a/gdb/python/lib/gdb/backtrace.py b/gdb/python/lib/gdb/backtrace.py
new file mode 100644
index 0000000..6bb4fb1
--- /dev/null
+++ b/gdb/python/lib/gdb/backtrace.py
@@ -0,0 +1,42 @@
+# Filtering backtrace.
+
+# Copyright (C) 2008, 2011 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 <http://www.gnu.org/licenses/>.
+
+import gdb
+import itertools
+
+# Our only exports.
+__all__ = ['push_frame_filter', 'create_frame_filter']
+
+frame_filter = None
+
+def push_frame_filter (constructor):
+ """Register a new backtrace filter class with the 'backtrace' command.
+The filter will be passed an iterator as an argument. The iterator
+will return gdb.Frame-like objects. The filter should in turn act as
+an iterator returning such objects."""
+ global frame_filter
+ if frame_filter == None:
+ frame_filter = constructor
+ else:
+ frame_filter = lambda iterator, filter = frame_filter: constructor (filter (iterator))
+
+def create_frame_filter (iter):
+ global frame_filter
+ if frame_filter is None:
+ return iter
+ return frame_filter (iter)
+
diff --git a/gdb/python/lib/gdb/command/alias.py b/gdb/python/lib/gdb/command/alias.py
new file mode 100644
index 0000000..96b6618
--- /dev/null
+++ b/gdb/python/lib/gdb/command/alias.py
@@ -0,0 +1,59 @@
+# Alias command.
+
+# Copyright (C) 2008 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 <http://www.gnu.org/licenses/>.
+
+import gdb
+
+class AliasImplementation (gdb.Command):
+ def __init__ (self, name, real, doc):
+ # Have to set __doc__ before the super init call.
+ # It would be nice if gdb's help looked up __doc__ dynamically.
+ self.__doc__ = doc
+ # Note: no good way to complete :(
+ super (AliasImplementation, self).__init__ (name, gdb.COMMAND_NONE)
+ self.real = real
+
+ def invoke(self, arg, from_tty):
+ gdb.execute (self.real + ' ' + arg, from_tty)
+
+class AliasCommand (gdb.Command):
+ """Alias one command to another.
+In the simplest form, the first word is the name of the alias, and
+the remaining words are the the expansion.
+An '=' by itself can be used to define a multi-word alias; words
+before the '=' are the name of the new command."""
+
+ def __init__ (self):
+ # Completion is not quite right here.
+ super (AliasCommand, self).__init__ ("alias", gdb.COMMAND_NONE,
+ gdb.COMPLETE_COMMAND)
+
+ def invoke (self, arg, from_tty):
+ self.dont_repeat ()
+ # Without some form of quoting we can't alias a multi-word
+ # command to another command.
+ args = arg.split()
+ try:
+ start = args.index ('=')
+ end = start + 1
+ except ValueError:
+ start = 1
+ end = 1
+ target = " ".join(args[end:])
+ AliasImplementation (" ".join (args[0:start]), target,
+ "This command is an alias for '%s'." % target)
+
+AliasCommand()
diff --git a/gdb/python/lib/gdb/command/backtrace.py b/gdb/python/lib/gdb/command/backtrace.py
new file mode 100644
index 0000000..eeea909
--- /dev/null
+++ b/gdb/python/lib/gdb/command/backtrace.py
@@ -0,0 +1,106 @@
+# New backtrace command.
+
+# Copyright (C) 2008, 2009, 2011 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 <http://www.gnu.org/licenses/>.
+
+import gdb
+import gdb.backtrace
+import itertools
+from gdb.FrameIterator import FrameIterator
+from gdb.FrameWrapper import FrameWrapper
+import sys
+
+class ReverseBacktraceParameter (gdb.Parameter):
+ """The new-backtrace command can show backtraces in 'reverse' order.
+This means that the innermost frame will be printed last.
+Note that reverse backtraces are more expensive to compute."""
+
+ set_doc = "Enable or disable reverse backtraces."
+ show_doc = "Show whether backtraces will be printed in reverse order."
+
+ def __init__(self):
+ gdb.Parameter.__init__ (self, "reverse-backtrace",
+ gdb.COMMAND_STACK, gdb.PARAM_BOOLEAN)
+ # Default to compatibility with gdb.
+ self.value = False
+
+class FilteringBacktrace (gdb.Command):
+ """Print backtrace of all stack frames, or innermost COUNT frames.
+With a negative argument, print outermost -COUNT frames.
+Use of the 'full' qualifier also prints the values of the local variables.
+Use of the 'raw' qualifier avoids any filtering by loadable modules.
+"""
+
+ def __init__ (self):
+ # FIXME: this is not working quite well enough to replace
+ # "backtrace" yet.
+ gdb.Command.__init__ (self, "new-backtrace", gdb.COMMAND_STACK)
+ self.reverse = ReverseBacktraceParameter()
+
+ def reverse_iter (self, iter):
+ result = []
+ for item in iter:
+ result.append (item)
+ result.reverse()
+ return result
+
+ def final_n (self, iter, x):
+ result = []
+ for item in iter:
+ result.append (item)
+ return result[x:]
+
+ def invoke (self, arg, from_tty):
+ i = 0
+ count = 0
+ filter = True
+ full = False
+
+ for word in arg.split (" "):
+ if word == '':
+ continue
+ elif word == 'raw':
+ filter = False
+ elif word == 'full':
+ full = True
+ else:
+ count = int (word)
+
+ # FIXME: provide option to start at selected frame
+ # However, should still number as if starting from newest
+ newest_frame = gdb.newest_frame()
+ iter = itertools.imap (FrameWrapper,
+ FrameIterator (newest_frame))
+ if filter:
+ iter = gdb.backtrace.create_frame_filter (iter)
+
+ # Now wrap in an iterator that numbers the frames.
+ iter = itertools.izip (itertools.count (0), iter)
+
+ # Reverse if the user wanted that.
+ if self.reverse.value:
+ iter = self.reverse_iter (iter)
+
+ # Extract sub-range user wants.
+ if count < 0:
+ iter = self.final_n (iter, count)
+ elif count > 0:
+ iter = itertools.islice (iter, 0, count)
+
+ for pair in iter:
+ sys.stdout.write ("#%-2d" % pair[0])
+ pair[1].describe (sys.stdout, full)
+
+FilteringBacktrace()
diff --git a/gdb/python/lib/gdb/command/ignore_errors.py b/gdb/python/lib/gdb/command/ignore_errors.py
new file mode 100644
index 0000000..6fa48ff
--- /dev/null
+++ b/gdb/python/lib/gdb/command/ignore_errors.py
@@ -0,0 +1,37 @@
+# Ignore errors in user commands.
+
+# Copyright (C) 2008 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 <http://www.gnu.org/licenses/>.
+
+import gdb
+
+class IgnoreErrorsCommand (gdb.Command):
+ """Execute a single command, ignoring all errors.
+Only one-line commands are supported.
+This is primarily useful in scripts."""
+
+ def __init__ (self):
+ super (IgnoreErrorsCommand, self).__init__ ("ignore-errors",
+ gdb.COMMAND_OBSCURE,
+ # FIXME...
+ gdb.COMPLETE_COMMAND)
+
+ def invoke (self, arg, from_tty):
+ try:
+ gdb.execute (arg, from_tty)
+ except:
+ pass
+
+IgnoreErrorsCommand ()
diff --git a/gdb/python/lib/gdb/command/pahole.py b/gdb/python/lib/gdb/command/pahole.py
new file mode 100644
index 0000000..21a0bf0
--- /dev/null
+++ b/gdb/python/lib/gdb/command/pahole.py
@@ -0,0 +1,75 @@
+# pahole command for gdb
+
+# Copyright (C) 2008, 2009 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 <http://www.gnu.org/licenses/>.
+
+import gdb
+
+class Pahole (gdb.Command):
+ """Show the holes in a structure.
+This command takes a single argument, a type name.
+It prints the type and displays comments showing where holes are."""
+
+ def __init__ (self):
+ super (Pahole, self).__init__ ("pahole", gdb.COMMAND_NONE,
+ gdb.COMPLETE_SYMBOL)
+
+ def pahole (self, type, level, name):
+ if name is None:
+ name = ''
+ tag = type.tag
+ if tag is None:
+ tag = ''
+ print '%sstruct %s {' % (' ' * (2 * level), tag)
+ bitpos = 0
+ for field in type.fields ():
+ # Skip static fields.
+ if not hasattr (field, ('bitpos')):
+ continue
+
+ ftype = field.type.strip_typedefs()
+
+ if bitpos != field.bitpos:
+ hole = field.bitpos - bitpos
+ print ' /* XXX %d bit hole, try to pack */' % hole
+ bitpos = field.bitpos
+ if field.bitsize > 0:
+ fieldsize = field.bitsize
+ else:
+ # TARGET_CHAR_BIT here...
+ fieldsize = 8 * ftype.sizeof
+
+ # TARGET_CHAR_BIT
+ print ' /* %3d %3d */' % (int (bitpos / 8), int (fieldsize / 8)),
+ bitpos = bitpos + fieldsize
+
+ if ftype.code == gdb.TYPE_CODE_STRUCT:
+ self.pahole (ftype, level + 1, field.name)
+ else:
+ print ' ' * (2 + 2 * level),
+ print '%s %s' % (str (ftype), field.name)
+
+ print ' ' * (14 + 2 * level),
+ print '} %s' % name
+
+ def invoke (self, arg, from_tty):
+ type = gdb.lookup_type (arg)
+ type = type.strip_typedefs ()
+ if type.code != gdb.TYPE_CODE_STRUCT:
+ raise TypeError, '%s is not a struct type' % arg
+ print ' ' * 14,
+ self.pahole (type, 0, '')
+
+Pahole()
diff --git a/gdb/python/lib/gdb/command/require.py b/gdb/python/lib/gdb/command/require.py
new file mode 100644
index 0000000..1fbc1e8
--- /dev/null
+++ b/gdb/python/lib/gdb/command/require.py
@@ -0,0 +1,57 @@
+# Demand-loading commands.
+
+# Copyright (C) 2008, 2009 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 <http://www.gnu.org/licenses/>.
+
+import gdb
+import os
+
+class RequireCommand (gdb.Command):
+ """Prefix command for requiring features."""
+
+ def __init__ (self):
+ super (RequireCommand, self).__init__ ("require",
+ gdb.COMMAND_SUPPORT,
+ gdb.COMPLETE_NONE,
+ True)
+
+class RequireSubcommand (gdb.Command):
+ """Demand-load a command by name."""
+
+ def __init__ (self, name):
+ self.__doc__ = "Demand-load a %s by name." % name
+ super (RequireSubcommand, self).__init__ ("require %s" % name,
+ gdb.COMMAND_SUPPORT)
+ self.name = name
+
+ def invoke (self, arg, from_tty):
+ for cmd in arg.split():
+ exec ('import gdb.' + self.name + '.' + cmd, globals ())
+
+ def complete (self, text, word):
+ dir = gdb.pythondir + '/gdb/' + self.name
+ result = []
+ for file in os.listdir(dir):
+ if not file.startswith (word) or not file.endswith ('.py'):
+ continue
+ feature = file[0:-3]
+ if feature == 'require' or feature == '__init__':
+ continue
+ result.append (feature)
+ return result
+
+RequireCommand()
+RequireSubcommand("command")
+RequireSubcommand("function")
diff --git a/gdb/python/lib/gdb/command/upto.py b/gdb/python/lib/gdb/command/upto.py
new file mode 100644
index 0000000..faf54ed
--- /dev/null
+++ b/gdb/python/lib/gdb/command/upto.py
@@ -0,0 +1,129 @@
+# upto command.
+
+# Copyright (C) 2009 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 <http://www.gnu.org/licenses/>.
+
+import gdb
+import re
+from gdb.FrameIterator import FrameIterator
+from gdb.FrameWrapper import FrameWrapper
+
+class UptoPrefix (gdb.Command):
+ def __init__ (self):
+ super (UptoPrefix, self).__init__ ("upto", gdb.COMMAND_STACK,
+ prefix = True)
+
+class UptoImplementation (gdb.Command):
+ def __init__ (self, subcommand):
+ super (UptoImplementation, self).__init__ ("upto " + subcommand,
+ gdb.COMMAND_STACK)
+
+ def search (self):
+ saved = gdb.selected_frame ()
+ iter = FrameIterator (saved)
+ found = False
+ try:
+ for frame in iter:
+ frame.select ()
+ try:
+ if self.filter (frame):
+ wrapper = FrameWrapper (frame)
+ wrapper.describe (sys.stdout, False)
+ return
+ except:
+ pass
+ except:
+ pass
+ saved.select ()
+ raise RuntimeError, 'Could not find a matching frame'
+
+ def invoke (self, arg, from_tty):
+ self.rx = re.compile (arg)
+ self.search ()
+
+class UptoSymbolCommand (UptoImplementation):
+ """Select and print some calling stack frame, based on symbol.
+The argument is a regular expression. This command moves up the
+stack, stopping at the first frame whose symbol matches the regular
+expression."""
+
+ def __init__ (self):
+ super (UptoSymbolCommand, self).__init__ ("symbol")
+
+ def filter (self, frame):
+ name = frame.name ()
+ if name is not None:
+ if self.rx.search (name) is not None:
+ return True
+ return False
+
+class UptoSourceCommand (UptoImplementation):
+ """Select and print some calling stack frame, based on source file.
+The argument is a regular expression. This command moves up the
+stack, stopping at the first frame whose source file name matches the
+regular expression."""
+
+ def __init__ (self):
+ super (UptoSourceCommand, self).__init__ ("source")
+
+ def filter (self, frame):
+ name = frame.find_sal ().symtab.filename
+ if name is not None:
+ if self.rx.search (name) is not None:
+ return True
+ return False
+
+class UptoObjectCommand (UptoImplementation):
+ """Select and print some calling stack frame, based on object file.
+The argument is a regular expression. This command moves up the
+stack, stopping at the first frame whose object file name matches the
+regular expression."""
+
+ def __init__ (self):
+ super (UptoObjectCommand, self).__init__ ("object")
+
+ def filter (self, frame):
+ name = frame.find_sal ().symtab.objfile.filename
+ if name is not None:
+ if self.rx.search (name) is not None:
+ return True
+ return False
+
+class UptoWhereCommand (UptoImplementation):
+ """Select and print some calling stack frame, based on expression.
+The argument is an expression. This command moves up the stack,
+parsing and evaluating the expression in each frame. This stops when
+the expression evaluates to a non-zero (true) value."""
+
+ def __init__ (self):
+ super (UptoWhereCommand, self).__init__ ("where")
+
+ def filter (self, frame):
+ try:
+ if gdb.parse_and_eval (self.expression):
+ return True
+ except:
+ pass
+ return False
+
+ def invoke (self, arg, from_tty):
+ self.expression = arg
+ self.search ()
+
+UptoPrefix ()
+UptoSymbolCommand ()
+UptoSourceCommand ()
+UptoObjectCommand ()
+UptoWhereCommand ()
diff --git a/gdb/python/lib/gdb/function/__init__.py b/gdb/python/lib/gdb/function/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/gdb/python/lib/gdb/function/__init__.py
@@ -0,0 +1 @@
+
diff --git a/gdb/python/lib/gdb/function/caller_is.py b/gdb/python/lib/gdb/function/caller_is.py
new file mode 100644
index 0000000..2b9c5c7
--- /dev/null
+++ b/gdb/python/lib/gdb/function/caller_is.py
@@ -0,0 +1,58 @@
+# Caller-is functions.
+
+# Copyright (C) 2008 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 <http://www.gnu.org/licenses/>.
+
+import gdb
+import re
+
+class CallerIs (gdb.Function):
+ """Return True if the calling function's name is equal to a string.
+This function takes one or two arguments.
+The first argument is the name of a function; if the calling function's
+name is equal to this argument, this function returns True.
+The optional second argument tells this function how many stack frames
+to traverse to find the calling function. The default is 1."""
+
+ def __init__ (self):
+ super (CallerIs, self).__init__ ("caller_is")
+
+ def invoke (self, name, nframes = 1):
+ frame = gdb.selected_frame ()
+ while nframes > 0:
+ frame = frame.older ()
+ nframes = nframes - 1
+ return frame.name () == name.string ()
+
+class CallerMatches (gdb.Function):
+ """Return True if the calling function's name matches a string.
+This function takes one or two arguments.
+The first argument is a regular expression; if the calling function's
+name is matched by this argument, this function returns True.
+The optional second argument tells this function how many stack frames
+to traverse to find the calling function. The default is 1."""
+
+ def __init__ (self):
+ super (CallerMatches, self).__init__ ("caller_matches")
+
+ def invoke (self, name, nframes = 1):
+ frame = gdb.selected_frame ()
+ while nframes > 0:
+ frame = frame.older ()
+ nframes = nframes - 1
+ return re.match (name.string (), frame.name ()) is not None
+
+CallerIs()
+CallerMatches()
diff --git a/gdb/python/lib/gdb/function/in_scope.py b/gdb/python/lib/gdb/function/in_scope.py
new file mode 100644
index 0000000..debb3bb
--- /dev/null
+++ b/gdb/python/lib/gdb/function/in_scope.py
@@ -0,0 +1,47 @@
+# In-scope function.
+
+# Copyright (C) 2008 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 <http://www.gnu.org/licenses/>.
+
+import gdb
+
+class InScope (gdb.Function):
+ """Return True if all the given variables or macros are in scope.
+Takes one argument for each variable name to be checked."""
+
+ def __init__ (self):
+ super (InScope, self).__init__ ("in_scope")
+
+ def invoke (self, *vars):
+ if len (vars) == 0:
+ raise TypeError, "in_scope takes at least one argument"
+
+ # gdb.Value isn't hashable so it can't be put in a map.
+ # Convert to string first.
+ wanted = set (map (lambda x: x.string (), vars))
+ found = set ()
+ block = gdb.selected_frame ().block ()
+ while block:
+ for sym in block:
+ if (sym.is_argument or sym.is_constant
+ or sym.is_function or sym.is_variable):
+ if sym.name in wanted:
+ found.add (sym.name)
+
+ block = block.superblock
+
+ return wanted == found
+
+InScope ()
diff --git a/gdb/python/py-type.c b/gdb/python/py-type.c
index c010420..3f4a261 100644
--- a/gdb/python/py-type.c
+++ b/gdb/python/py-type.c
@@ -29,6 +29,8 @@
#include "language.h"
#include "vec.h"
#include "bcache.h"
+#include "observer.h"
+#include "gdb_assert.h"
typedef struct pyty_type_object
{
@@ -37,11 +39,19 @@ typedef struct pyty_type_object
/* If a Type object is associated with an objfile, it is kept on a
doubly-linked list, rooted in the objfile. This lets us copy the
- underlying struct type when the objfile is deleted. */
+ underlying struct type when the objfile is deleted.
+
+ With NULL objfile Type still can be doubly-linked in the list
+ PYTY_OBJECTS_DISCARDABLE. */
struct pyty_type_object *prev;
struct pyty_type_object *next;
} type_object;
+#if 0
+/* First element of a doubly-linked list of TYPE_DISCARDABLE Types. */
+static type_object *pyty_objects_discardable;
+#endif
+
static PyTypeObject type_object_type;
/* A Field object. */
@@ -919,8 +929,63 @@ typy_richcompare (PyObject *self, PyObject *other, int op)
+/* Key associated with each objfile pointing to the first element of
+ a doubly-linked list of Types associated with this objfile. */
static const struct objfile_data *typy_objfile_data_key;
+/* Link TYPE_OBJ to its appropriate list. Either to its objfile associated one
+ or at least to the global list for TYPE_DISCARDABLE Types. Permanent types
+ do not get linked anywhere. */
+static void
+typy_link (type_object *type_obj)
+{
+ type_obj->prev = NULL;
+
+ if (type_obj->type && TYPE_OBJFILE (type_obj->type))
+ {
+ struct objfile *objfile = TYPE_OBJFILE (type_obj->type);
+
+ type_obj->next = objfile_data (objfile, typy_objfile_data_key);
+ if (type_obj->next)
+ type_obj->next->prev = type_obj;
+ set_objfile_data (objfile, typy_objfile_data_key, type_obj);
+ }
+#if 0
+ else if (type_obj->type && TYPE_DISCARDABLE (type_obj->type))
+ {
+ type_obj->next = pyty_objects_discardable;
+ if (type_obj->next)
+ type_obj->next->prev = type_obj;
+ pyty_objects_discardable = type_obj;
+ }
+#endif
+ else
+ type_obj->next = NULL;
+}
+
+/* Unlink TYPE_OBJ from its current list. Permanent types are not linked
+ anywhere and this function has no effect on them. */
+static void
+typy_unlink (type_object *type_obj)
+{
+ if (type_obj->prev)
+ type_obj->prev->next = type_obj->next;
+ else if (type_obj->type && TYPE_OBJFILE (type_obj->type))
+ {
+ /* Must reset head of list. */
+ struct objfile *objfile = TYPE_OBJFILE (type_obj->type);
+
+ set_objfile_data (objfile, typy_objfile_data_key, type_obj->next);
+ }
+#if 0
+ else if (pyty_objects_discardable == type_obj)
+ pyty_objects_discardable = type_obj->next;
+#endif
+
+ if (type_obj->next)
+ type_obj->next->prev = type_obj->prev;
+}
+
static void
save_objfile_types (struct objfile *objfile, void *datum)
{
@@ -938,12 +1003,13 @@ save_objfile_types (struct objfile *objfile, void *datum)
{
type_object *next = obj->next;
- htab_empty (copied_types);
+ gdb_assert (TYPE_OBJFILE (obj->type) == objfile);
+ typy_unlink (obj);
- obj->type = copy_type_recursive (objfile, obj->type, copied_types);
+ obj->type = copy_type_recursive (obj->type, copied_types);
- obj->next = NULL;
- obj->prev = NULL;
+ gdb_assert (TYPE_OBJFILE (obj->type) == NULL);
+ typy_link (obj);
obj = next;
}
@@ -954,43 +1020,28 @@ save_objfile_types (struct objfile *objfile, void *datum)
}
static void
-set_type (type_object *obj, struct type *type)
+typy_dealloc (PyObject *obj)
{
- obj->type = type;
- obj->prev = NULL;
- if (type && TYPE_OBJFILE (type))
- {
- struct objfile *objfile = TYPE_OBJFILE (type);
+ type_object *type_obj = (type_object *) obj;
- obj->next = objfile_data (objfile, typy_objfile_data_key);
- if (obj->next)
- obj->next->prev = obj;
- set_objfile_data (objfile, typy_objfile_data_key, obj);
- }
- else
- obj->next = NULL;
+ typy_unlink (type_obj);
+
+ type_obj->ob_type->tp_free (obj);
}
+#if 0
+/* Call type_mark_used for any TYPEs referenced from this GDB source file. */
static void
-typy_dealloc (PyObject *obj)
+typy_types_mark_used (void)
{
- type_object *type = (type_object *) obj;
-
- if (type->prev)
- type->prev->next = type->next;
- else if (type->type && TYPE_OBJFILE (type->type))
- {
- /* Must reset head of list. */
- struct objfile *objfile = TYPE_OBJFILE (type->type);
-
- if (objfile)
- set_objfile_data (objfile, typy_objfile_data_key, type->next);
- }
- if (type->next)
- type->next->prev = type->prev;
+ type_object *type_obj;
- type->ob_type->tp_free (type);
+ for (type_obj = pyty_objects_discardable;
+ type_obj != NULL;
+ type_obj = type_obj->next)
+ type_mark_used (type_obj->type);
}
+#endif
/* Create a new Type referring to TYPE. */
PyObject *
@@ -1000,7 +1051,10 @@ type_to_type_object (struct type *type)
type_obj = PyObject_New (type_object, &type_object_type);
if (type_obj)
- set_type (type_obj, type);
+ {
+ type_obj->type = type;
+ typy_link (type_obj);
+ }
return (PyObject *) type_obj;
}
@@ -1074,6 +1128,10 @@ gdbpy_initialize_types (void)
Py_INCREF (&field_object_type);
PyModule_AddObject (gdb_module, "Field", (PyObject *) &field_object_type);
+
+#if 0
+ observer_attach_mark_used (typy_types_mark_used);
+#endif
}
diff --git a/gdb/python/py-value.c b/gdb/python/py-value.c
index 4381d52..5dff3e2 100644
--- a/gdb/python/py-value.c
+++ b/gdb/python/py-value.c
@@ -28,6 +28,7 @@
#include "infcall.h"
#include "expression.h"
#include "cp-abi.h"
+#include "observer.h"
#ifdef HAVE_PYTHON
@@ -1210,6 +1211,19 @@ gdbpy_is_value_object (PyObject *obj)
return PyObject_TypeCheck (obj, &value_object_type);
}
+#if 0
+/* Call type_mark_used for any TYPEs referenced from this GDB source file. */
+
+static void
+python_types_mark_used (void)
+{
+ value_object *iter;
+
+ for (iter = values_in_python; iter; iter = iter->next)
+ type_mark_used (value_type (iter->value));
+}
+#endif
+
void
gdbpy_initialize_values (void)
{
@@ -1220,6 +1234,10 @@ gdbpy_initialize_values (void)
PyModule_AddObject (gdb_module, "Value", (PyObject *) &value_object_type);
values_in_python = NULL;
+
+#if 0
+ observer_attach_mark_used (python_types_mark_used);
+#endif
}
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 90d5dc8..ec4823e 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -49,8 +49,11 @@ static int gdbpy_should_print_stack = 1;
#include "linespec.h"
#include "source.h"
#include "version.h"
+#include "inferior.h"
+#include "gdbthread.h"
#include "target.h"
#include "gdbthread.h"
+#include "event-top.h"
static PyMethodDef GdbMethods[];
@@ -769,6 +772,53 @@ gdbpy_print_stack (void)
/* Return the current Progspace.
There always is one. */
+/* True if 'gdb -P' was used, false otherwise. */
+static int running_python_script;
+
+/* True if we are currently in a call to 'gdb.cli', false otherwise. */
+static int in_cli;
+
+/* Enter the command loop. */
+
+static PyObject *
+gdbpy_cli (PyObject *unused1, PyObject *unused2)
+{
+ if (! running_python_script || in_cli)
+ return PyErr_Format (PyExc_RuntimeError, "cannot invoke CLI recursively");
+
+ in_cli = 1;
+ cli_command_loop ();
+ in_cli = 0;
+
+ Py_RETURN_NONE;
+}
+
+/* Set up the Python argument vector and evaluate a script. This is
+ used to implement 'gdb -P'. */
+
+void
+run_python_script (int argc, char **argv)
+{
+ FILE *input;
+
+ /* We never free this, since we plan to exit at the end. */
+ ensure_python_env (get_current_arch (), current_language);
+
+ running_python_script = 1;
+ PySys_SetArgv (argc - 1, argv + 1);
+ input = fopen (argv[0], "r");
+ if (! input)
+ {
+ fprintf (stderr, "could not open %s: %s\n", argv[0], strerror (errno));
+ exit (1);
+ }
+ PyRun_SimpleFile (input, argv[0]);
+ fclose (input);
+ exit (0);
+}
+
+
+
static PyObject *
gdbpy_get_current_progspace (PyObject *unused1, PyObject *unused2)
@@ -1194,6 +1244,8 @@ static PyMethodDef GdbMethods[] =
"Get a value from history" },
{ "execute", (PyCFunction) execute_gdb_command, METH_VARARGS | METH_KEYWORDS,
"Execute a gdb command" },
+ { "cli", gdbpy_cli, METH_NOARGS,
+ "Enter the gdb CLI" },
{ "parameter", gdbpy_parameter, METH_VARARGS,
"Return a gdb parameter's value" },
diff --git a/gdb/python/python.h b/gdb/python/python.h
index ce0eb35..14572f4 100644
--- a/gdb/python/python.h
+++ b/gdb/python/python.h
@@ -32,6 +32,8 @@ void eval_python_from_control_command (struct command_line *);
void source_python_script (FILE *stream, const char *file);
+void run_python_script (int argc, char **argv);
+
int apply_val_pretty_printer (struct type *type, const gdb_byte *valaddr,
int embedded_offset, CORE_ADDR address,
struct ui_file *stream, int recurse,
diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
index 432da99..78c6b1c 100644
--- a/gdb/solib-svr4.c
+++ b/gdb/solib-svr4.c
@@ -1276,7 +1276,8 @@ svr4_in_dynsym_resolve_code (CORE_ADDR pc)
&& pc < info->interp_text_sect_high)
|| (pc >= info->interp_plt_sect_low
&& pc < info->interp_plt_sect_high)
- || in_plt_section (pc, NULL));
+ || in_plt_section (pc, NULL)
+ || in_gnu_ifunc_stub (pc));
}
/* Given an executable's ABFD and target, compute the entry-point
diff --git a/gdb/somread.c b/gdb/somread.c
index 70831a0..baf68ea 100644
--- a/gdb/somread.c
+++ b/gdb/somread.c
@@ -439,6 +439,7 @@ static const struct sym_fns som_sym_fns =
default_symfile_segments, /* Get segment information from a file. */
NULL,
default_symfile_relocate, /* Relocate a debug section. */
+ NULL, /* sym_get_probes */
&psym_functions
};
diff --git a/gdb/stack.c b/gdb/stack.c
index 0888b69..c3efd5b 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -366,6 +366,7 @@ print_frame_args (struct symbol *func, struct frame_info *frame,
{
const struct language_defn *language;
struct value_print_options opts;
+ struct cleanup *old_chain;
/* Use the appropriate language to display our symbol,
unless the user forced the language to a specific
@@ -378,7 +379,13 @@ print_frame_args (struct symbol *func, struct frame_info *frame,
get_raw_print_options (&opts);
opts.deref_ref = 0;
opts.summary = summary;
+
+ /* Frame may be needed for check_typedef of TYPE_DYNAMIC. */
+ old_chain = make_cleanup_restore_selected_frame ();
+ select_frame (frame);
common_val_print (val, stb->stream, 2, &opts, language);
+ do_cleanups (old_chain);
+
ui_out_field_stream (uiout, "value", stb);
}
else
diff --git a/gdb/stap-probe.c b/gdb/stap-probe.c
new file mode 100644
index 0000000..eb2fb7f
--- /dev/null
+++ b/gdb/stap-probe.c
@@ -0,0 +1,1939 @@
+/* Systemtap probe support for GDB.
+
+ Copyright (C) 2011 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/>. */
+
+#include "defs.h"
+#include "stap-probe.h"
+#include "vec.h"
+#include "ui-out.h"
+#include "gdb_regex.h"
+#include "objfiles.h"
+#include "arch-utils.h"
+#include "command.h"
+#include "filenames.h"
+#include "value.h"
+#include "exceptions.h"
+#include "ax.h"
+#include "ax-gdb.h"
+#include "user-regs.h"
+#include "complaints.h"
+#include "cli/cli-utils.h"
+
+#include <ctype.h>
+
+enum stap_arg_bitness
+{
+ STAP_ARG_BITNESS_UNDEFINED,
+ STAP_ARG_BITNESS_32BIT_UNSIGNED,
+ STAP_ARG_BITNESS_32BIT_SIGNED,
+ STAP_ARG_BITNESS_64BIT_UNSIGNED,
+ STAP_ARG_BITNESS_64BIT_SIGNED,
+};
+
+struct stap_probe_arg
+{
+ /* The bitness of this argument. */
+ enum stap_arg_bitness bitness;
+
+ /* The string representing this argument. */
+ char *arg_str;
+};
+
+#define STAP_MAX_ARGS 10
+
+struct stap_args_info
+{
+ /* The number of valid parsed arguments. */
+ int n_args;
+
+ /* The probe to which these arguments belong. */
+ struct stap_probe *probe;
+
+ /* Information about each argument. */
+ struct stap_probe_arg *arg;
+};
+
+/* Struct that contains all the necessary information to evaluate
+ an expression. */
+
+struct stap_evaluation_info
+{
+ /* The constant pointer which holds the expression. This is primarily
+ used for printing error messages. Evaluation functions should
+ not modify this pointer directly; instead, they should use the
+ EXP_BUFFER pointer below. */
+ const char *saved_expr;
+
+ /* Modifiable version of the above pointer. */
+ char *exp_buf;
+
+ /* The pointer to the current gdbarch. */
+ struct gdbarch *gdbarch;
+
+ /* The pointer to the current frame, used when accessing registers'
+ contents. */
+ struct frame_info *frame;
+
+ /* The bitness specified for this argument. */
+ enum stap_arg_bitness bitness;
+
+ /* Flag to indicate if we are compiling an agent expression. */
+ int compiling_p;
+
+ /* If the above flag is true (one), this field will contain the
+ pointer to the agent expression. */
+ struct agent_expr *aexpr;
+
+ /* The value we are modifying (for agent expression). */
+ struct axs_value *value;
+};
+
+/* This dummy variable is used when parsing a probe's argument fails.
+ In this case, the number of arguments for this probe is zero, so that's
+ why this variable is useful. */
+
+static struct stap_args_info dummy_stap_args_info =
+ { 0, NULL, NULL };
+
+/* Evaluation function for probe's argument expressions. LHS represents
+ the left side of the expression, and PREC is the precedence of the
+ last operator identified before calling the function. */
+
+static struct value *
+stap_evaluate_probe_argument_2 (struct stap_evaluation_info *eval_info,
+ struct value *lhs, int prec);
+
+static struct value *
+stap_evaluate_conditionally (struct stap_evaluation_info *eval_info);
+
+static void
+stap_skip_whitespace_cond (char **s, int inside_paren)
+{
+ if (inside_paren)
+ *s = skip_spaces (*s);
+}
+
+static int
+stap_parse_arg (const char **p)
+{
+ char *cur = (char *) *p;
+ int done = 0;
+ int paren_open = 0;
+
+ while (!done)
+ {
+ switch (*cur)
+ {
+ case ' ': case 0:
+ /* If we're here, then we have already parsed everything
+ from this argument. */
+ if (paren_open)
+ return 0;
+ done = 1;
+ break;
+
+ case '(':
+ ++paren_open;
+ ++cur;
+ stap_skip_whitespace_cond (&cur, paren_open);
+ break;
+
+ case ')':
+ if (!paren_open)
+ return 0;
+
+ --paren_open;
+ ++cur;
+ if (paren_open)
+ cur = skip_spaces (cur);
+ break;
+
+ case '+': case '-':
+ case '*': case '/':
+ case '>': case '<': case '|': case '&':
+ case '^': case '!':
+ {
+ char c = *cur;
+
+ ++cur;
+ switch (*cur)
+ {
+ case '>':
+ if (c != '<' && c != '>')
+ return 0;
+
+ ++cur;
+ break;
+
+ case '<':
+ if (c != '<')
+ return 0;
+
+ ++cur;
+ break;
+
+ case '=':
+ if (c != '=' && c != '<' && c != '>' && c != '!')
+ return 0;
+
+ ++cur;
+ break;
+
+ case '|':
+ if (c != '|')
+ return 0;
+
+ ++cur;
+ break;
+
+ case '&':
+ if (c != '&')
+ return 0;
+
+ ++cur;
+ break;
+
+ default:
+ break;
+ }
+ /* Infix operators take two arguments, one on either
+ side. Skipping the whitespaces that may happen on the
+ right side. */
+ stap_skip_whitespace_cond (&cur, paren_open);
+ }
+ break;
+
+ case '%':
+ {
+ ++cur;
+ stap_skip_whitespace_cond (&cur, paren_open);
+ if (*cur >= 'a' && *cur <= 'z')
+ {
+ /* We're dealing with a register name. */
+ while (isalnum (*cur))
+ ++cur;
+
+ stap_skip_whitespace_cond (&cur, paren_open);
+
+ /* Some registers (e.g. floating-point register stack
+ registers on Intel i386) have the following syntax:
+
+ `%st(0)', `%st(1)', and so on.
+
+ So it's ok to expect parenthesis here. */
+ if (*cur == '(')
+ {
+ ++cur;
+ stap_skip_whitespace_cond (&cur, paren_open);
+ if (!isdigit (*cur))
+ /* This is an error, since we only expect numbers
+ inside this parenthesis. */
+ return 0;
+ ++cur;
+ stap_skip_whitespace_cond (&cur, paren_open);
+ if (*cur != ')')
+ /* We only expect one number. */
+ return 0;
+ ++cur;
+ stap_skip_whitespace_cond (&cur, paren_open);
+ }
+ }
+ }
+ break;
+
+ case '$':
+ {
+ /* This is an integer constant. */
+ ++cur;
+ stap_skip_whitespace_cond (&cur, paren_open);
+
+ while (isdigit (*cur))
+ ++cur;
+
+ stap_skip_whitespace_cond (&cur, paren_open);
+ }
+ break;
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ {
+ char *old = cur;
+
+ /* Number. */
+ while (isdigit (*cur))
+ ++cur;
+
+ /* We have to do a lookahead here, because the user may
+ input `2 + 2' (with spaces), and this is not an error. */
+ cur = skip_spaces (cur);
+
+ switch (*cur)
+ {
+ case '+': case '-':
+ /* We may find the `@' sign, and it means that the
+ argument has finished, so we shouldn't advance the
+ pointer. */
+ if (cur[1] && (cur[1] == '4' || cur[1] == '8')
+ && cur[2] && cur[2] == '@')
+ {
+ cur = old;
+ goto fin;
+ }
+ break;
+
+ case '*': case '/': case '>': case '<':
+ case '|': case '&': case '^': case '!':
+ /* This is a binary operation, which means we'll
+ have to find another number after the operator. */
+ break;
+
+ case '(':
+ /* We may also have sentences in the form:
+
+ `4 (%rax)' */
+ break;
+ }
+ }
+fin:
+ break;
+ }
+ }
+
+ *p = cur;
+
+ return 1;
+}
+
+static void
+stap_free_args_info (void *args_info_ptr)
+{
+ struct stap_args_info *a = (struct stap_args_info *) args_info_ptr;
+ int i;
+
+ for (i = 0; i < STAP_MAX_ARGS; i++)
+ {
+ xfree (a->arg->arg_str);
+ }
+
+ xfree (a->arg);
+ xfree (a);
+}
+
+void
+stap_parse_probe_arguments (struct stap_probe *probe)
+{
+ struct stap_args_info *args_info;
+ struct cleanup *back_to;
+ const char *cur = probe->args;
+ int current_arg = -1;
+ enum
+ {
+ NEW_ARG,
+ BITNESS,
+ PARSE_ARG,
+ } current_state;
+
+ /* For now, we assume everything is not going to work. */
+ probe->parsed_args = &dummy_stap_args_info;
+
+ if (!cur || !*cur || *cur == ':')
+ return;
+
+ args_info = xmalloc (sizeof (struct stap_args_info));
+ back_to = make_cleanup (stap_free_args_info, args_info);
+ args_info->arg = xcalloc (STAP_MAX_ARGS, sizeof (struct stap_probe_arg));
+
+ /* Ok, let's start. */
+ current_state = NEW_ARG;
+
+ while (*cur)
+ {
+ switch (current_state)
+ {
+ case NEW_ARG:
+ ++current_arg;
+
+ if (current_arg >= STAP_MAX_ARGS)
+ {
+ complaint (&symfile_complaints,
+ _("probe `%s' has more arguments than the maximum "
+ "allowed"), probe->name);
+ do_cleanups (back_to);
+ return;
+ }
+
+ current_state = BITNESS;
+ break;
+
+ case BITNESS:
+ {
+ enum stap_arg_bitness b;
+ int got_minus = 0;
+
+ /* We expect to find something like:
+
+ N@OP
+
+ Where `N' can be [+,-][4,8]. This is not mandatory, so
+ we check it here. If we don't find it, go to the next
+ state. */
+ if ((*cur == '-' && cur[1] && cur[2] != '@')
+ && cur[1] != '@')
+ {
+ current_state = PARSE_ARG;
+ args_info->arg[current_arg].bitness
+ = STAP_ARG_BITNESS_UNDEFINED;
+ break;
+ }
+
+ if (*cur == '-')
+ {
+ /* Discard the `-'. */
+ ++cur;
+ got_minus = 1;
+ }
+
+ if (*cur == '4')
+ b = got_minus ? STAP_ARG_BITNESS_32BIT_SIGNED
+ : STAP_ARG_BITNESS_32BIT_UNSIGNED;
+ else if (*cur == '8')
+ b = got_minus ? STAP_ARG_BITNESS_64BIT_SIGNED
+ : STAP_ARG_BITNESS_64BIT_UNSIGNED;
+ else
+ {
+ /* We have an error, because we don't expect anything
+ except 4 and 8. */
+ complaint (&symfile_complaints,
+ _("unrecognized bitness `%c' for probe `%s'"),
+ *cur, probe->name);
+ do_cleanups (back_to);
+ return;
+ }
+
+ args_info->arg[current_arg].bitness = b;
+ /* Discard the number and the `@' sign. */
+ cur += 2;
+ /* Move on. */
+ current_state = PARSE_ARG;
+ }
+ break;
+
+ case PARSE_ARG:
+ {
+ const char *start = cur;
+
+ if (!stap_parse_arg (&cur))
+ {
+ /* We have tried to parse this argument, but it's
+ malformed. This is an error. */
+ do_cleanups (back_to);
+ return;
+ }
+
+ args_info->arg[current_arg].arg_str
+ = savestring (start, cur - start);
+ /* Start it over again. */
+ cur = skip_spaces ((char *) cur);
+ current_state = NEW_ARG;
+ }
+ break;
+ }
+
+ if (!*cur && current_state != NEW_ARG)
+ {
+ /* We reached the end of the argument string, but we're
+ still in the middle of the process of parsing an argument.
+ It means the argument string is malformed. */
+ complaint (&symfile_complaints,
+ _("malformed argument for probe `%s'"),
+ probe->name);
+ do_cleanups (back_to);
+ return;
+ }
+ }
+
+ args_info->n_args = current_arg + 1;
+ args_info->arg = xrealloc (args_info->arg,
+ args_info->n_args
+ * sizeof (struct stap_probe_arg));
+ args_info->probe = probe;
+
+ probe->parsed_args = args_info;
+
+ discard_cleanups (back_to);
+}
+
+int
+stap_get_probe_argument_count (const struct stap_probe *probe)
+{
+ if (!probe->parsed_args)
+ stap_parse_probe_arguments ((struct stap_probe *) probe);
+
+ return probe->parsed_args->n_args;
+}
+
+/* Returns the operator precedence level of OP, or zero if the operator
+ code was not recognized.
+ The levels were taken from the gas manual. */
+
+static int
+stap_get_operator_prec (enum exp_opcode op)
+{
+ switch (op)
+ {
+ case BINOP_LOGICAL_OR:
+ return 1;
+
+ case BINOP_LOGICAL_AND:
+ return 2;
+
+ case BINOP_ADD: case BINOP_SUB:
+ case BINOP_EQUAL: case BINOP_NOTEQUAL:
+ case BINOP_LESS: case BINOP_LEQ:
+ case BINOP_GTR: case BINOP_GEQ:
+ return 3;
+
+ case BINOP_BITWISE_IOR: case BINOP_BITWISE_AND:
+ case BINOP_BITWISE_XOR: case UNOP_LOGICAL_NOT:
+ return 4;
+
+ case BINOP_MUL: case BINOP_DIV: case BINOP_REM:
+ case BINOP_LSH: case BINOP_RSH:
+ return 5;
+
+ default:
+ return 0;
+ }
+}
+
+/* Given S, this function reads the operator in it and fills the OP
+ pointer with its code. Returns 1 on success, zero if the operator
+ was not recognized. */
+
+static int
+stap_get_opcode (char **s, enum exp_opcode *op)
+{
+ char c = **s;
+ int ret = 1;
+
+ *s += 1;
+
+ switch (c)
+ {
+ case '*':
+ *op = BINOP_MUL;
+ break;
+
+ case '/':
+ *op = BINOP_DIV;
+ break;
+
+ case '%':
+ {
+ if (isalpha (**s))
+ {
+ /* Dealing with a register name. */
+ ret = 0;
+ break;
+ }
+
+ *op = BINOP_REM;
+ }
+ break;
+
+ case '<':
+ *op = BINOP_LESS;
+ if (**s == '<')
+ {
+ *s += 1;
+ *op = BINOP_LSH;
+ }
+ else if (**s == '=')
+ {
+ *s += 1;
+ *op = BINOP_LEQ;
+ }
+ else if (**s == '>')
+ {
+ *s += 1;
+ *op = BINOP_NOTEQUAL;
+ }
+ break;
+
+ case '>':
+ *op = BINOP_GTR;
+ if (**s == '>')
+ {
+ *s += 1;
+ *op = BINOP_RSH;
+ }
+ else if (**s == '=')
+ {
+ *s += 1;
+ *op = BINOP_GEQ;
+ }
+ break;
+
+ case '|':
+ *op = BINOP_BITWISE_IOR;
+ if (**s == '|')
+ {
+ *s += 1;
+ *op = BINOP_LOGICAL_OR;
+ }
+ break;
+
+ case '&':
+ *op = BINOP_BITWISE_AND;
+ if (**s == '&')
+ {
+ *s += 1;
+ *op = BINOP_LOGICAL_AND;
+ }
+ break;
+
+ case '^':
+ *op = BINOP_BITWISE_XOR;
+ break;
+
+ case '!':
+ *op = UNOP_LOGICAL_NOT;
+ break;
+
+ case '+':
+ *op = BINOP_ADD;
+ break;
+
+ case '-':
+ *op = BINOP_SUB;
+ break;
+
+ case '=':
+ if (**s != '=')
+ {
+ ret = 0;
+ break;
+ }
+ *op = BINOP_EQUAL;
+ break;
+
+ default:
+ /* We didn't find any operator. */
+ *s -= 1;
+ return 0;
+ }
+
+ return ret;
+}
+
+static void
+stap_opcode_to_ax (struct stap_evaluation_info *eval_info,
+ enum exp_opcode opcode)
+{
+ struct agent_expr *expr = eval_info->aexpr;
+
+ switch (opcode)
+ {
+ case BINOP_MUL:
+ ax_simple (expr, aop_mul);
+ break;
+
+ case BINOP_DIV:
+ /* FIXME: Should we sign-extend the operands? */
+ ax_simple (expr, aop_div_signed);
+ break;
+
+ case BINOP_REM:
+ ax_simple (expr, aop_rem_unsigned);
+ break;
+
+ case BINOP_LESS:
+ /* FIXME: Should we sign-extend the operands? */
+ ax_simple (expr, aop_less_signed);
+ break;
+
+ case BINOP_LEQ:
+ /* A <= B is !(B < A) */
+ ax_simple (expr, aop_swap);
+ ax_simple (expr, aop_less_signed);
+ ax_simple (expr, aop_log_not);
+ break;
+
+ case BINOP_GTR:
+ /* A > B is B < A */
+ ax_simple (expr, aop_swap);
+ ax_simple (expr, aop_less_signed);
+ break;
+
+ case BINOP_GEQ:
+ /* A >= B is !(A < B) */
+ ax_simple (expr, aop_less_signed);
+ ax_simple (expr, aop_log_not);
+ break;
+
+ case BINOP_NOTEQUAL:
+ ax_simple (expr, aop_equal);
+ ax_simple (expr, aop_log_not);
+ break;
+
+ case BINOP_LSH:
+ ax_simple (expr, aop_lsh);
+ break;
+
+ case BINOP_RSH:
+ ax_simple (expr, aop_rsh_unsigned);
+ break;
+
+ case BINOP_BITWISE_IOR:
+ ax_simple (expr, aop_bit_or);
+ break;
+
+ case BINOP_LOGICAL_OR:
+ /* FIXME: ????? */
+// ax_simple (expr, aop_
+ break;
+
+ case BINOP_BITWISE_AND:
+ ax_simple (expr, aop_bit_and);
+ break;
+
+ case BINOP_LOGICAL_AND:
+ /* FIXME: ???? */
+ break;
+
+ case BINOP_BITWISE_XOR:
+ ax_simple (expr, aop_bit_xor);
+ break;
+
+ case UNOP_LOGICAL_NOT:
+ ax_simple (expr, aop_log_not);
+ break;
+
+ case BINOP_ADD:
+ ax_simple (expr, aop_add);
+ break;
+
+ case BINOP_SUB:
+ ax_simple (expr, aop_sub);
+ break;
+
+ case BINOP_EQUAL:
+ ax_simple (expr, aop_equal);
+ break;
+
+ default:
+ error (_("Invalid operator."));
+ }
+}
+
+/* Returns 1 if *S is an operator, zero otherwise. */
+
+static int
+stap_is_operator (char *s)
+{
+ char op;
+
+ if (!s || !*s)
+ return 0;
+
+ op = *s;
+
+ if (*s == '%' && isalpha (s[1]))
+ /* Register name. */
+ return 0;
+
+ return (op == '+' || op == '-' || op == '*' || op == '/'
+ || op == '>' || op == '<' || op == '!' || op == '^'
+ || op == '|' || op == '&' || op == '%' || op == '=');
+}
+
+/* This function fetches the value of the register whose
+ name starts in the expression buffer. It also applies any register
+ displacements (e.g., `-4(%eax)'), and indirects the contents of the
+ register (e.g., `(%eax)'). It returns RET if the operation has succeeded,
+ or calls `error' otherwise. */
+
+static struct value *
+stap_fetch_reg_value (struct stap_evaluation_info *eval_info,
+ struct value *displacement)
+{
+ const char *start;
+ char *s = eval_info->exp_buf;
+ struct gdbarch *gdbarch = eval_info->gdbarch;
+ struct frame_info *frame = eval_info->frame;
+ enum stap_arg_bitness bitness = eval_info->bitness;
+#define REG_NAME_MAX_SIZE 20
+ char regname[REG_NAME_MAX_SIZE + 1];
+ int len, regnum, indirect_p = 0;
+ struct value *ret;
+
+ /* The function which called us did not check if the expression
+ buffer was empty. */
+ gdb_assert (s && *s);
+
+ /* Valid register name on x86 platforms are:
+
+ [paren]%{a-z0-9}[paren]
+
+ Let's check for that here. */
+ if (*s == '(')
+ {
+ ++s;
+ if (!*s || *s != '%'
+ || (*s == '%' && !isalpha (s[1])))
+ error (_("Invalid register name on expression `%s'."),
+ eval_info->saved_expr);
+ ++s;
+ /* The presence of parenthesis means that we want to indirect
+ the register. */
+ indirect_p = 1;
+ }
+ else if (*s == '%')
+ {
+ ++s;
+ if (!*s || !isalpha (*s))
+ error (_("Invalid register name on expression `%s'."),
+ eval_info->saved_expr);
+ }
+ else
+ error (_("Invalid register name on expression `%s'."),
+ eval_info->saved_expr);
+
+ if (displacement && !indirect_p)
+ /* We cannot apply displacement to non-indirect register access. */
+ error (_("Trying to apply displacement without indirecting register "
+ "on expression `%s'."), eval_info->saved_expr);
+
+ /* Ok, let's calculate the size of the register name. */
+ start = s;
+ while (isalnum (*s))
+ ++s;
+
+ len = s - start;
+
+ if (*s == ')')
+ ++s;
+
+ if (len >= REG_NAME_MAX_SIZE)
+ error (_("The register name is greater than the supported size "
+ "on expression `%s'."), eval_info->saved_expr);
+
+ strncpy (regname, start, len);
+ regname[len] = '\0';
+
+ /* Translating the register name into the corresponding number. */
+ regnum = user_reg_map_name_to_regnum (gdbarch, regname, len);
+
+ if (regnum == -1)
+ error (_("Invalid register name `%s' on expression `%s'."),
+ regname, eval_info->saved_expr);
+
+ if (eval_info->compiling_p)
+ ax_reg (eval_info->aexpr, regnum);
+ else
+ ret = value_of_register (regnum, frame);
+
+ if (indirect_p)
+ {
+ struct type *t = NULL;
+ enum agent_op aop;
+
+ /* If the user has specified that the register must be indirected,
+ we should know what's the correct type to cast it before making
+ the indirection. This type corresponds to the bitness specified
+ before the `@' sign on the argument string, or it defaults to
+ `unsigned long' if the `@' were not present. */
+
+ switch (bitness)
+ {
+ case STAP_ARG_BITNESS_UNDEFINED:
+ if (eval_info->compiling_p)
+ aop = aop_ref32;
+ else
+ t = lookup_pointer_type
+ (builtin_type (gdbarch)->builtin_unsigned_long);
+ break;
+
+ case STAP_ARG_BITNESS_32BIT_SIGNED:
+ if (eval_info->compiling_p)
+ aop = aop_ref32;
+ else
+ t = lookup_pointer_type
+ (builtin_type (gdbarch)->builtin_int32);
+ break;
+
+ case STAP_ARG_BITNESS_32BIT_UNSIGNED:
+ if (eval_info->compiling_p)
+ aop = aop_ref32;
+ else
+ t = lookup_pointer_type
+ (builtin_type (gdbarch)->builtin_uint32);
+ break;
+
+ case STAP_ARG_BITNESS_64BIT_SIGNED:
+ if (eval_info->compiling_p)
+ aop = aop_ref64;
+ else
+ t = lookup_pointer_type
+ (builtin_type (gdbarch)->builtin_int64);
+ break;
+
+ case STAP_ARG_BITNESS_64BIT_UNSIGNED:
+ if (eval_info->compiling_p)
+ aop = aop_ref64;
+ else
+ t = lookup_pointer_type
+ (builtin_type (gdbarch)->builtin_uint64);
+ break;
+
+ default:
+ internal_error (__FILE__, __LINE__,
+ _("Undefined bitness for probe."));
+ break;
+ }
+
+ if (displacement)
+ {
+ if (eval_info->compiling_p)
+ {
+ ax_const_l (eval_info->aexpr, value_as_long (displacement));
+ /* FIXME: Is this correct? */
+ ax_simple (eval_info->aexpr, aop_add);
+ }
+ else
+ ret = value_ptradd (ret, value_as_long (displacement));
+ }
+
+ if (eval_info->compiling_p)
+ ax_simple (eval_info->aexpr, aop);
+ else
+ {
+ ret = value_cast (t, ret);
+ ret = value_ind (ret);
+ }
+ }
+
+ /* Updating the expression buffer pointer, because we have made
+ some modifications to it before. */
+ eval_info->exp_buf = s;
+
+ return eval_info->compiling_p ? (struct value *) 1 : ret;
+}
+
+/* This function tries to evaluate a single operand of the expression.
+
+ Single operands can be:
+
+ - unary operators `-' and `~';
+ - integer constants (beginning with `$');
+ - register access, with/out displacement and indirection. */
+
+static struct value *
+stap_evaluate_single_operand (struct stap_evaluation_info *eval_info)
+{
+ struct gdbarch *gdbarch = eval_info->gdbarch;
+ struct frame_info *frame = eval_info->frame;
+ enum stap_arg_bitness bitness = eval_info->bitness;
+ struct value *res;
+
+ switch (*eval_info->exp_buf)
+ {
+ case '-': case '~':
+ {
+ char c = *eval_info->exp_buf;
+
+ /* This is a binary operator (either `-' or `~').
+
+ If it is followed by a parenthesis, and this parenthesis
+ is NOT followed by a `%', then we are dealing with an expression
+ like `-(2 + 3)' or `~(2 + 3)'. We just have to treat separately
+ and return the result after applying the operation (`-' or `~').
+
+ If it is followed by a digit, then we have only one choice: it
+ is a displacement argument for a register access, like
+ `-4(%eax)'. It also means that the operator can *only* be `-',
+ and the characters immediately after the number *must* be `(%'.
+
+ If it is followed by a `$', then it is an integer constant, and
+ we should apply the correct operation to it. */
+
+ ++eval_info->exp_buf;
+ eval_info->exp_buf = skip_spaces (eval_info->exp_buf);
+ if (*eval_info->exp_buf
+ && *eval_info->exp_buf == '('
+ && eval_info->exp_buf[1] != '%')
+ {
+ struct value *tmp_res;
+
+ /* We're not dealing with a register name, but with an
+ expression like `-(2 + 3)' or `~(2 + 3)'. We first have
+ to evaluate the right side of the expression (i.e., the
+ parenthesis), and then apply the specified operation
+ (either `-' or `~') to it. */
+ tmp_res = stap_evaluate_conditionally (eval_info);
+
+ if (c == '-')
+ {
+ if (eval_info->compiling_p)
+ {
+ /* We have to add `-1' to the stack, and multiply
+ the two values. */
+ ax_const_l (eval_info->aexpr, -1);
+ ax_simple (eval_info->aexpr, aop_mul);
+ }
+ else
+ res = value_neg (tmp_res);
+ }
+ else
+ {
+ if (eval_info->compiling_p)
+ ax_simple (eval_info->aexpr, aop_bit_not);
+ else
+ res = value_complement (tmp_res);
+ }
+ }
+ else if (isdigit (*eval_info->exp_buf))
+ {
+ int number;
+
+ /* This is a number, so it MUST be a register displacement.
+ The only operator allowed here is `-', it MUST be
+ followed by a number, and the number MUST be followed by
+ `(%'. */
+ if (c != '-')
+ error (_("Invalid operator `%c' for register displacement "
+ "on expression `%s'."), c, eval_info->saved_expr);
+
+ number = strtol (eval_info->exp_buf,
+ &eval_info->exp_buf, 0) * -1;
+
+ if (!*eval_info->exp_buf
+ || *eval_info->exp_buf != '('
+ || (*eval_info->exp_buf == '('
+ && eval_info->exp_buf[1] != '%'))
+ error (_("Invalid method of indirecting a register on "
+ "expression `%s'."), eval_info->saved_expr);
+
+ res
+ = value_from_longest (builtin_type (gdbarch)->builtin_int,
+ number);
+
+ res = stap_fetch_reg_value (eval_info, res);
+ }
+ else if (*eval_info->exp_buf == '$')
+ {
+ int number;
+
+ /* Last case. We are dealing with an integer constant, so
+ we must read it and then apply the necessary operation,
+ either `-' or `~'. */
+ ++eval_info->exp_buf;
+ number = strtol (eval_info->exp_buf,
+ &eval_info->exp_buf, 0);
+
+ if (!eval_info->compiling_p)
+ res
+ = value_from_longest (builtin_type (gdbarch)->builtin_int,
+ number);
+
+ if (eval_info->compiling_p)
+ ax_const_l (eval_info->aexpr, number);
+
+ eval_info->exp_buf = skip_spaces (eval_info->exp_buf);
+
+ if (c == '-')
+ {
+ if (eval_info->compiling_p)
+ ax_simple (eval_info->aexpr, aop_log_not);
+ else
+ res = value_neg (res);
+ }
+ else
+ {
+ if (eval_info->compiling_p)
+ ax_simple (eval_info->aexpr, aop_bit_not);
+ else
+ res = value_complement (res);
+ }
+ }
+ else
+ error (_("Invalid operand to unary operator `%c' on "
+ "expression `%s'."), c, eval_info->saved_expr);
+ }
+ break;
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ {
+ int number = strtol (eval_info->exp_buf, &eval_info->exp_buf, 0);
+
+ /* This is a register displacement with a positive value. We read
+ the number, and then check for the mandatory `(%' part. */
+ if (!*eval_info->exp_buf
+ || !(*eval_info->exp_buf == '('
+ && eval_info->exp_buf[1] == '%'))
+ error (_("Invalid register access on expression `%s'."),
+ eval_info->saved_expr);
+
+ res = value_from_longest (builtin_type (gdbarch)->builtin_int,
+ number);
+
+ res = stap_fetch_reg_value (eval_info, res);
+ }
+ break;
+
+ case '$':
+ {
+ int number;
+
+ /* This is an integer constant. We just have to read the number
+ and return it. */
+ ++eval_info->exp_buf;
+ eval_info->exp_buf = skip_spaces (eval_info->exp_buf);
+
+ number = strtol (eval_info->exp_buf, &eval_info->exp_buf, 0);
+
+ if (eval_info->compiling_p)
+ ax_const_l (eval_info->aexpr, number);
+ else
+ res = value_from_longest (builtin_type (gdbarch)->builtin_int,
+ number);
+
+ eval_info->exp_buf = skip_spaces (eval_info->exp_buf);
+ }
+ break;
+
+ case '(': case '%':
+ {
+ /* Register access, with or without indirection. */
+ res = stap_fetch_reg_value (eval_info, /*displacement=*/NULL);
+ }
+ break;
+
+ default:
+ {
+ error (_("Operator `%c' not recognized on expression `%s'."),
+ *eval_info->exp_buf, eval_info->saved_expr);
+ }
+ }
+
+ return eval_info->compiling_p ? (struct value *) 1 : res;
+}
+
+/* This function is responsible for checking the necessary type of evaluation
+ depending on what is the next "thing" in the buffer. Valid values are:
+
+ - Unary operators;
+ - Integer constants;
+ - Register displacement, indirection, and direct access;
+ - Parenthesized operand. */
+
+static struct value *
+stap_evaluate_conditionally (struct stap_evaluation_info *eval_info)
+{
+ char *s = eval_info->exp_buf;
+ struct value *ret = NULL;
+
+ if (*s == '-' || *s == '~' /* Unary operators. */
+ || *s == '$' /* Number (integer constant). */
+ || (isdigit (*s) && s[1] == '(' && s[2] == '%') /* Displacement. */
+ || (*s == '(' && s[1] == '%') /* Register indirection. */
+ || (*s == '%' && isalpha (s[1]))) /* Register value. */
+ /* This is a single operand, so just evaluate it and return. */
+ ret = stap_evaluate_single_operand (eval_info);
+ else if (*s == '(')
+ {
+ /* We are dealing with a parenthesized operand. It means we
+ have to evaluate it as it was a separate expression, without
+ left-side or precedence. */
+ ++eval_info->exp_buf;
+ eval_info->exp_buf = skip_spaces (eval_info->exp_buf);
+
+ ret = stap_evaluate_probe_argument_2 (eval_info,
+ /*lhs=*/NULL, /*prec=*/0);
+
+ if (*eval_info->exp_buf != ')')
+ error (_("Missign close-paren on expression `%s'."),
+ eval_info->saved_expr);
+ ++eval_info->exp_buf;
+ eval_info->exp_buf = skip_spaces (eval_info->exp_buf);
+ }
+ else
+ error (_("Cannot evaluate expression `%s'."),
+ eval_info->saved_expr);
+
+ return ret;
+}
+
+static struct value *
+stap_evaluate_probe_argument_2 (struct stap_evaluation_info *eval_info,
+ struct value *lhs, int prec)
+{
+ struct value *rhs = NULL;
+ int compiling_p = eval_info->compiling_p;
+
+ /* This is an operator-precedence parser and evaluator.
+
+ We work with left- and right-sides of expressions, and
+ evaluate them depending on the precedence of the operators
+ we find. */
+
+ eval_info->exp_buf = skip_spaces (eval_info->exp_buf);
+
+ if (!lhs)
+ /* We were called without a left-side, either because this is the
+ first call, or because we were called to evaluate a parenthesized
+ expression. It doesn't really matter; we have to evaluate the
+ left-side in order to continue the process. */
+ lhs = stap_evaluate_conditionally (eval_info);
+
+ /* Start to evaluate the right-side, and to "join" left and right sides
+ depending on the operation specified.
+
+ This loop shall continue until we run out of characters in the input,
+ or until we find a close-parenthesis, which means that we've reached
+ the end of a sub-expression. */
+ while (eval_info->exp_buf
+ && *eval_info->exp_buf
+ && *eval_info->exp_buf != ')')
+ {
+ char *tmp_exp_buf;
+ enum exp_opcode opcode;
+ int cur_prec;
+
+ if (!stap_is_operator (eval_info->exp_buf))
+ error (_("Invalid operator `%c' on expression `%s'."),
+ *eval_info->exp_buf, eval_info->saved_expr);
+
+ /* We have to save the current value of the expression buffer because
+ the `stap_get_opcode' modifies it in order to get the current
+ operator. If this operator's precedence is lower than PREC, we
+ should return and not advance the expression buffer pointer. */
+ tmp_exp_buf = eval_info->exp_buf;
+ stap_get_opcode (&tmp_exp_buf, &opcode);
+
+ cur_prec = stap_get_operator_prec (opcode);
+ if (cur_prec < prec)
+ /* If the precedence of the operator that we are seeing now is
+ lower than the precedence of the first operator seen before
+ this evaluation process began, it means we should stop evaluating
+ and return. */
+ break;
+
+ eval_info->exp_buf = tmp_exp_buf;
+ eval_info->exp_buf = skip_spaces (eval_info->exp_buf);
+
+ /* Evaluate the right-side of the expression. */
+ rhs = stap_evaluate_conditionally (eval_info);
+
+ /* While we still have operators, try to evaluate another
+ right-side, but using the current right-side as a left-side. */
+ while (*eval_info->exp_buf
+ && stap_is_operator (eval_info->exp_buf))
+ {
+ enum exp_opcode lookahead_opcode;
+ int lookahead_prec;
+
+ /* Saving the current expression buffer position. The explanation
+ is the same as above. */
+ tmp_exp_buf = eval_info->exp_buf;
+ stap_get_opcode (&tmp_exp_buf, &lookahead_opcode);
+ lookahead_prec = stap_get_operator_prec (lookahead_opcode);
+
+ if (lookahead_prec <= prec)
+ /* If we are dealing with an operator whose precedence is lower
+ than the first one, just abandon the attempt. */
+ break;
+
+ rhs = stap_evaluate_probe_argument_2 (eval_info,
+ rhs, lookahead_prec);
+ }
+
+ /* Now, "join" both left and right sides into one left-side, using
+ the specified operator. */
+ if (compiling_p)
+ stap_opcode_to_ax (eval_info, opcode);
+ else
+ lhs = value_binop (lhs, rhs, opcode);
+ }
+
+ return lhs;
+}
+
+/* This function fills the necessary arguments for the evaluation function
+ to work. */
+
+#define TEST 0
+static struct value *
+stap_evaluate_probe_argument_1 (struct objfile *objfile,
+ const struct stap_probe *probe,
+ struct frame_info *frame,
+ int n)
+{
+ struct stap_evaluation_info eval_info;
+ char *s = (char *) probe->parsed_args->arg[n].arg_str;
+ struct value *res, *vs[4];
+#if TEST /*TESTING*/
+ const char *args[4] = { "$2",
+ "$2 + $3 * $4 + $5",
+ "-($2 + $3)",
+ "(~($2) * $3) / ($1 + $1)" };
+ int i;
+#endif
+
+ /* Filling necessary information for evaluation function. */
+ eval_info.saved_expr = s;
+ eval_info.exp_buf = s;
+ eval_info.gdbarch = get_objfile_arch (objfile);
+ eval_info.frame = frame;
+ eval_info.bitness = probe->parsed_args->arg[n].bitness;
+ /* We are not compiling to an agent expression. */
+ eval_info.compiling_p = 0;
+ eval_info.aexpr = NULL;
+
+ res = stap_evaluate_probe_argument_2 (&eval_info,
+ /*lhs=*/NULL, /*prec=*/0);
+#if TEST /* TESTING */
+ for (i = 0; i < 4; i++)
+ {
+ eval_info.saved_expr = (const char *) args[i];
+ eval_info.exp_buf = (char *) args[i];
+ vs[i] = stap_evaluate_probe_argument_2 (&eval_info,
+ /*lhs=*/NULL, /*prec=*/0);
+
+ fprintf_unfiltered (gdb_stdout, "%ld\n", value_as_long (vs[i]));
+ }
+#endif
+
+ if (!res)
+ error (_("Could not evaluate expression `%s'."),
+ eval_info.saved_expr);
+
+ return res;
+}
+
+struct value *
+stap_evaluate_probe_argument (struct objfile *objfile,
+ const struct stap_probe *probe,
+ struct frame_info *frame,
+ int n)
+{
+ if (!probe->parsed_args)
+ stap_parse_probe_arguments ((struct stap_probe *) probe);
+
+ if (!probe->parsed_args->arg
+ || n >= probe->parsed_args->n_args)
+ return NULL;
+
+ return stap_evaluate_probe_argument_1 (objfile, probe, frame, n);
+}
+
+static void
+stap_compile_to_ax_1 (struct objfile *objfile,
+ const struct stap_probe *probe,
+ struct agent_expr *expr,
+ struct axs_value *value,
+ int n)
+{
+ struct stap_evaluation_info eval_info;
+ char *s = (char *) probe->parsed_args->arg[n].arg_str;
+
+ /* Filling necessary information for evaluation function. */
+ eval_info.saved_expr = s;
+ eval_info.exp_buf = s;
+ eval_info.gdbarch = expr->gdbarch;
+ eval_info.frame = NULL;
+ eval_info.bitness = probe->parsed_args->arg[n].bitness;
+ /* We are compiling to an agent expression. */
+ eval_info.compiling_p = 1;
+ eval_info.aexpr = expr;
+
+ stap_evaluate_probe_argument_2 (&eval_info,
+ /*lhs=*/NULL, /*prec=*/0);
+}
+
+void
+stap_compile_to_ax (struct objfile *objfile,
+ const struct stap_probe *probe,
+ struct agent_expr *expr,
+ struct axs_value *value,
+ int n)
+{
+ if (!probe->parsed_args)
+ stap_parse_probe_arguments ((struct stap_probe *) probe);
+
+ if (!probe->parsed_args->arg
+ || n >= probe->parsed_args->n_args)
+ return;
+
+ stap_compile_to_ax_1 (objfile, probe, expr, value, n);
+}
+
+/* See documentation in stap-probe.h. */
+
+struct value *
+stap_safe_evaluate_at_pc (struct frame_info *frame, int n)
+{
+ const struct stap_probe *probe;
+ struct objfile *objfile;
+ int n_probes;
+
+ probe = find_probe_by_pc (get_frame_pc (frame), &objfile);
+ if (!probe)
+ return NULL;
+ gdb_assert (objfile->sf && objfile->sf->sym_probe_fns);
+
+ n_probes
+ = objfile->sf->sym_probe_fns->sym_get_probe_argument_count (objfile,
+ probe);
+ if (n >= n_probes)
+ return NULL;
+
+ return objfile->sf->sym_probe_fns->sym_evaluate_probe_argument (objfile,
+ probe,
+ frame,
+ n);
+}
+
+void
+stap_free_parsed_args (struct stap_args_info *parsed_args)
+{
+ if (!parsed_args
+ || parsed_args == &dummy_stap_args_info
+ || parsed_args->n_args == 0)
+ return;
+
+ xfree (parsed_args->arg);
+ xfree (parsed_args);
+}
+
+/* A helper function to extract an argument from *ARG. An argument is
+ delimited by whitespace. The return value is either NULL if no
+ argument was found, or an xmalloc'd string. */
+
+static char *
+extract_arg (char **arg)
+{
+ char *result, *copy;
+
+ if (!*arg)
+ return NULL;
+
+ /* Find the start of the argument. */
+ *arg = skip_spaces (*arg);
+ if (! **arg)
+ return NULL;
+ result = *arg;
+
+ /* Find the end of the argument. */
+ *arg = skip_to_space (*arg + 1);
+
+ if (result == *arg)
+ return NULL;
+
+ copy = xmalloc (*arg - result + 1);
+ memcpy (copy, result, *arg - result);
+ copy[*arg - result] = '\0';
+
+ return copy;
+}
+
+/* A utility structure. A VEC of these is built when handling "info
+ probes". */
+
+struct stap_probe_and_objfile
+{
+ /* The probe. */
+ const struct stap_probe *probe;
+ /* The probe's objfile. */
+ struct objfile *objfile;
+};
+
+typedef struct stap_probe_and_objfile stap_entry;
+DEF_VEC_O (stap_entry);
+
+/* A helper function for collect_probes that compiles a regexp and
+ throws an exception on error. This installs a cleanup to free the
+ resulting pattern on success. If RX is NULL, this does nothing. */
+
+static void
+compile_rx_or_error (regex_t *pattern, const char *rx, const char *message)
+{
+ int code;
+
+ if (!rx)
+ return;
+
+ code = regcomp (pattern, rx, REG_NOSUB);
+ if (code == 0)
+ make_regfree_cleanup (pattern);
+ else
+ {
+ char *err = get_regcomp_error (code, pattern);
+
+ make_cleanup (xfree, err);
+ error (_("%s: %s"), message, err);
+ }
+}
+
+/* Make a vector of probes matching OBJNAME, PROVIDER, and PROBE.
+ Each argument is a regexp, or NULL, which matches anything. */
+
+static VEC (stap_entry) *
+collect_probes (char *objname, char *provider, char *probe)
+{
+ struct objfile *objfile;
+ VEC (stap_entry) *result = NULL;
+ struct cleanup *cleanup;
+ regex_t obj_pat, prov_pat, probe_pat;
+
+ cleanup = make_cleanup (VEC_cleanup (stap_entry), &result);
+
+ compile_rx_or_error (&prov_pat, provider, _("Invalid provider regexp"));
+ compile_rx_or_error (&probe_pat, probe, _("Invalid probe regexp"));
+ compile_rx_or_error (&obj_pat, objname, _("Invalid object file regexp"));
+
+ ALL_OBJFILES (objfile)
+ {
+ const struct stap_probe *probes;
+ int i, num_probes;
+
+ if (! objfile->sf || ! objfile->sf->sym_probe_fns)
+ continue;
+
+ if (objname)
+ {
+ if (regexec (&obj_pat, objfile->name, 0, NULL, 0) != 0)
+ continue;
+ }
+
+ probes = objfile->sf->sym_probe_fns->sym_get_probes (objfile, &num_probes);
+ for (i = 0; i < num_probes; ++i)
+ {
+ stap_entry entry;
+
+ if (provider)
+ {
+ if (regexec (&prov_pat, probes[i].provider, 0, NULL, 0) != 0)
+ continue;
+ }
+
+ if (probe)
+ {
+ if (regexec (&probe_pat, probes[i].name, 0, NULL, 0) != 0)
+ continue;
+ }
+
+ entry.probe = &probes[i];
+ entry.objfile = objfile;
+ VEC_safe_push (stap_entry, result, &entry);
+ }
+ }
+
+ discard_cleanups (cleanup);
+ return result;
+}
+
+/* A qsort comparison function for stap_entry objects. */
+
+static int
+compare_entries (const void *a, const void *b)
+{
+ const stap_entry *ea = a;
+ const stap_entry *eb = b;
+ int v;
+
+ v = strcmp (ea->probe->provider, eb->probe->provider);
+ if (v)
+ return v;
+
+ v = strcmp (ea->probe->name, eb->probe->name);
+ if (v)
+ return v;
+
+ if (ea->probe->address < eb->probe->address)
+ return -1;
+ if (ea->probe->address > eb->probe->address)
+ return 1;
+
+ return strcmp (ea->objfile->name, eb->objfile->name);
+}
+
+/* Implementation of the "info probes" command. */
+
+static void
+info_probes_command (char *arg, int from_tty)
+{
+ char *provider, *probe = NULL, *objname = NULL;
+ struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
+ VEC (stap_entry) *items;
+ int i, addr_width, any_found;
+ stap_entry *entry;
+
+ provider = extract_arg (&arg);
+ if (provider)
+ {
+ make_cleanup (xfree, provider);
+
+ probe = extract_arg (&arg);
+ if (probe)
+ {
+ make_cleanup (xfree, probe);
+
+ objname = extract_arg (&arg);
+ if (objname)
+ make_cleanup (xfree, objname);
+ }
+ }
+
+ items = collect_probes (objname, provider, probe);
+ make_cleanup (VEC_cleanup (stap_entry), &items);
+ make_cleanup_ui_out_table_begin_end (uiout, 5,
+ VEC_length (stap_entry, items),
+ "SystemTapProbes");
+
+ if (! VEC_empty (stap_entry, items))
+ qsort (VEC_address (stap_entry, items),
+ VEC_length (stap_entry, items),
+ sizeof (stap_entry),
+ compare_entries);
+
+ addr_width = 4 + (gdbarch_ptr_bit (get_current_arch ()) / 4);
+
+ ui_out_table_header (uiout, 10, ui_left, "provider", _("Provider"));
+ ui_out_table_header (uiout, 10, ui_left, "name", _("Name"));
+ ui_out_table_header (uiout, addr_width - 1, ui_left, "addr", _("Where"));
+ ui_out_table_header (uiout, addr_width - 1, ui_left, "semaphore",
+ _("Semaphore"));
+ ui_out_table_header (uiout, 30, ui_left, "object", _("Object"));
+ ui_out_table_body (uiout);
+
+ for (i = 0; VEC_iterate (stap_entry, items, i, entry); ++i)
+ {
+ struct cleanup *inner;
+
+ inner = make_cleanup_ui_out_tuple_begin_end (uiout, "probe");
+
+ ui_out_field_string (uiout, "provider", entry->probe->provider);
+ ui_out_field_string (uiout, "name", entry->probe->name);
+ ui_out_field_core_addr (uiout, "addr", get_current_arch (),
+ entry->probe->address);
+ if (entry->probe->sem_addr == 0)
+ ui_out_field_skip (uiout, "semaphore");
+ else
+ ui_out_field_core_addr (uiout, "semaphore", get_current_arch (),
+ entry->probe->sem_addr);
+ ui_out_field_string (uiout, "object", entry->objfile->name);
+ ui_out_text (uiout, "\n");
+
+ do_cleanups (inner);
+ }
+
+ any_found = ! VEC_empty (stap_entry, items);
+ do_cleanups (cleanup);
+
+ if (! any_found)
+ ui_out_message (uiout, 0, _("No probes matched.\n"));
+}
+
+
+
+const struct stap_probe *
+find_probe_in_objfile (struct objfile *objfile,
+ const char *provider,
+ const char *name)
+{
+ const struct stap_probe *probes;
+ int i, num_probes;
+
+ if (! objfile->sf || ! objfile->sf->sym_probe_fns)
+ return NULL;
+
+ probes = objfile->sf->sym_probe_fns->sym_get_probes (objfile, &num_probes);
+ for (i = 0; i < num_probes; ++i)
+ {
+ if (strcmp (probes[i].provider, provider) != 0)
+ continue;
+
+ if (strcmp (probes[i].name, name) != 0)
+ continue;
+
+ return &probes[i];
+ }
+
+ return NULL;
+}
+
+struct symtabs_and_lines
+parse_stap_probe (char **argptr)
+{
+ char *arg = extract_arg (argptr);
+ char *objfile_name = NULL, *provider = NULL, *name, *p;
+ struct cleanup *cleanup;
+ struct symtabs_and_lines result;
+ struct objfile *objfile;
+
+ result.sals = NULL;
+ result.nelts = 0;
+
+ /* The caller ensured that this starts with 'probe:'. */
+ gdb_assert (arg && strncmp (arg, "probe:", 6) == 0);
+ cleanup = make_cleanup (xfree, arg);
+ arg += 6;
+
+ /* Extract each word from the argument, separated by ":"s. */
+ p = strchr (arg, ':');
+ if (p == NULL)
+ {
+ /* This is `probe:name'. */
+ name = arg;
+ }
+ else
+ {
+ char *hold = p + 1;
+
+ *p = '\0';
+ p = strchr (hold, ':');
+ if (p == NULL)
+ {
+ /* This is `probe:provider:name'. */
+ provider = arg;
+ name = hold;
+ }
+ else
+ {
+ /* This is `probe:objfile:provider:name'. */
+ *p = '\0';
+ objfile_name = arg;
+ provider = hold;
+ name = p + 1;
+ }
+ }
+
+ if (*name == '\0')
+ error (_("no probe name specified"));
+ if (provider && *provider == '\0')
+ error (_("invalid provider name"));
+ if (objfile_name && *objfile_name == '\0')
+ error (_("invalid objfile name"));
+
+ ALL_OBJFILES (objfile)
+ {
+ const struct stap_probe *probes;
+ int i, num_probes;
+
+ if (! objfile->sf || ! objfile->sf->sym_probe_fns)
+ continue;
+
+ if (objfile_name
+ && FILENAME_CMP (objfile->name, objfile_name) != 0
+ && FILENAME_CMP (lbasename (objfile->name), objfile_name) != 0)
+ continue;
+
+ probes = objfile->sf->sym_probe_fns->sym_get_probes (objfile, &num_probes);
+ for (i = 0; i < num_probes; ++i)
+ {
+ struct symtab_and_line *sal;
+
+ if (provider && strcmp (probes[i].provider, provider) != 0)
+ continue;
+
+ if (strcmp (probes[i].name, name) != 0)
+ continue;
+
+ ++result.nelts;
+ result.sals = xrealloc (result.sals,
+ result.nelts * sizeof (struct symtab_and_line));
+ sal = &result.sals[result.nelts - 1];
+
+ init_sal (sal);
+
+ sal->pc = probes[i].address;
+ sal->explicit_pc = 1;
+ sal->section = find_pc_overlay (sal->pc);
+ sal->pspace = current_program_space;
+ sal->semaphore = probes[i].sem_addr;
+ }
+ }
+
+ if (result.nelts == 0)
+ throw_error (NOT_FOUND_ERROR,
+ _("No probe matching objfile=`%s', provider=`%s', name=`%s'"),
+ objfile_name ? objfile_name : _("<any>"),
+ provider ? provider : _("<any>"),
+ name);
+
+ do_cleanups (cleanup);
+
+ return result;
+}
+
+
+
+const struct stap_probe *
+find_probe_by_pc (CORE_ADDR pc, struct objfile **objfile_out)
+{
+ struct objfile *objfile;
+
+ ALL_OBJFILES (objfile)
+ {
+ const struct stap_probe *probes;
+ int i, num_probes;
+ stap_entry entry;
+
+ if (! objfile->sf || ! objfile->sf->sym_probe_fns)
+ continue;
+
+ /* If this proves too inefficient, we can replace with a hash. */
+ probes = objfile->sf->sym_probe_fns->sym_get_probes (objfile, &num_probes);
+ for (i = 0; i < num_probes; ++i)
+ {
+ if (probes[i].address == pc)
+ {
+ *objfile_out = objfile;
+ return &probes[i];
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/* This is called to compute the value of one of the $_probe_arg*
+ convenience variables. */
+
+static struct value *
+compute_probe_arg (struct gdbarch *arch, struct internalvar *ivar,
+ void *data)
+{
+ struct frame_info *frame = get_selected_frame (_("No frame selected"));
+ CORE_ADDR pc = get_frame_pc (frame);
+ int sel = (int) (uintptr_t) data;
+ struct objfile *objfile;
+ const struct stap_probe *pc_probe;
+ int n_probes;
+
+ /* SEL==10 means "_probe_argc". */
+ gdb_assert (sel >= 0 && sel <= 10);
+
+ pc_probe = find_probe_by_pc (pc, &objfile);
+ if (pc_probe == NULL)
+ error (_("No SystemTap probe at PC %s"), core_addr_to_string (pc));
+
+ n_probes
+ = objfile->sf->sym_probe_fns->sym_get_probe_argument_count (objfile,
+ pc_probe);
+ if (sel == 10)
+ return value_from_longest (builtin_type (arch)->builtin_int, n_probes);
+
+ gdb_assert (sel >= 0);
+ if (sel >= n_probes)
+ error (_("Invalid probe argument %d -- probe has %d arguments available"),
+ sel, n_probes);
+
+ return objfile->sf->sym_probe_fns->sym_evaluate_probe_argument (objfile,
+ pc_probe,
+ frame, sel);
+}
+
+/* This is called to compile one of the $_probe_arg* convenience
+ variables into an agent expression. */
+
+static void
+compile_probe_arg (struct internalvar *ivar, struct agent_expr *expr,
+ struct axs_value *value, void *data)
+{
+ CORE_ADDR pc = expr->scope;
+ int sel = (int) (uintptr_t) data;
+ struct objfile *objfile;
+ const struct stap_probe *pc_probe;
+ int n_probes;
+
+ /* SEL==10 means "_probe_argc". */
+ gdb_assert (sel >= 0 && sel <= 10);
+
+ pc_probe = find_probe_by_pc (pc, &objfile);
+ if (pc_probe == NULL)
+ error (_("No SystemTap probe at PC %s"), core_addr_to_string (pc));
+
+ n_probes
+ = objfile->sf->sym_probe_fns->sym_get_probe_argument_count (objfile,
+ pc_probe);
+ if (sel == 10)
+ {
+ value->kind = axs_rvalue;
+ value->type = builtin_type (expr->gdbarch)->builtin_int;
+ ax_const_l (expr, n_probes);
+ return;
+ }
+
+ gdb_assert (sel >= 0);
+ if (sel >= n_probes)
+ error (_("Invalid probe argument %d -- probe has %d arguments available"),
+ sel, n_probes);
+
+ /* FIXME: this is temporary until AX translation is implemented. */
+ if (!objfile->sf->sym_probe_fns->sym_compile_to_ax)
+ error (_("cannot translate `$_probe_arg%d' to bytecode"), sel);
+ objfile->sf->sym_probe_fns->sym_compile_to_ax (objfile, pc_probe,
+ expr, value, sel);
+}
+
+
+
+static const struct internalvar_funcs probe_funcs =
+{
+ compute_probe_arg,
+ compile_probe_arg,
+ NULL
+};
+
+void
+_initialize_stap_probe (void)
+{
+ add_info ("probes", info_probes_command, _("\
+Show available static probes.\n\
+Usage: info probes [PROVIDER [NAME [OBJECT]]]\n\
+Each argument is a regular expression, used to select probes.\n\
+PROVIDER matches probe provider names.\n\
+NAME matches the probe names.\n\
+OBJECT match the executable or shared library name."));
+
+ create_internalvar_type_lazy ("_probe_argc", &probe_funcs,
+ (void *) (uintptr_t) 10);
+ create_internalvar_type_lazy ("_probe_arg0", &probe_funcs,
+ (void *) (uintptr_t) 0);
+ create_internalvar_type_lazy ("_probe_arg1", &probe_funcs,
+ (void *) (uintptr_t) 1);
+ create_internalvar_type_lazy ("_probe_arg2", &probe_funcs,
+ (void *) (uintptr_t) 2);
+ create_internalvar_type_lazy ("_probe_arg3", &probe_funcs,
+ (void *) (uintptr_t) 3);
+ create_internalvar_type_lazy ("_probe_arg4", &probe_funcs,
+ (void *) (uintptr_t) 4);
+ create_internalvar_type_lazy ("_probe_arg5", &probe_funcs,
+ (void *) (uintptr_t) 5);
+ create_internalvar_type_lazy ("_probe_arg6", &probe_funcs,
+ (void *) (uintptr_t) 6);
+ create_internalvar_type_lazy ("_probe_arg7", &probe_funcs,
+ (void *) (uintptr_t) 7);
+ create_internalvar_type_lazy ("_probe_arg8", &probe_funcs,
+ (void *) (uintptr_t) 8);
+ create_internalvar_type_lazy ("_probe_arg9", &probe_funcs,
+ (void *) (uintptr_t) 9);
+}
diff --git a/gdb/stap-probe.h b/gdb/stap-probe.h
new file mode 100644
index 0000000..3a7941f
--- /dev/null
+++ b/gdb/stap-probe.h
@@ -0,0 +1,110 @@
+/* Systemtap probe support for GDB.
+
+ Copyright (C) 2011 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 (STAP_PROBE_H)
+#define STAP_PROBE_H 1
+
+struct stap_args_info;
+struct axs_value;
+
+struct stap_probe
+{
+ /* The provider of this probe. */
+ const char *provider;
+
+ /* The name of the probe. */
+ const char *name;
+
+ /* The address where the probe is inserted. */
+ CORE_ADDR address;
+
+ /* The address of the probe's semaphore, or 0 if this probe does not
+ have an associated semaphore. */
+ CORE_ADDR sem_addr;
+
+ /* Probe's arguments. Users should generally not examine this, but
+ should instead extract information about the arguments using the
+ methods provided in sym_probe_fns. */
+ const char *args;
+
+ /* Probe's arguments after parsing. This is an opaque structure that
+ will hold information about the arguments pointed by ARGS. */
+ struct stap_args_info *parsed_args;
+};
+
+
+/* A helper for linespec that decodes a stap probe specification. It
+ returns a symtabs_and_lines object and updates *ARGPTR or throws an
+ error. */
+
+extern struct symtabs_and_lines parse_stap_probe (char **argptr);
+
+/* Search OBJFILE for a probe with the given PROVIDER and NAME. If a
+ probe is found, return it. If no probe is found, return NULL. */
+
+extern const struct stap_probe *find_probe_in_objfile (struct objfile *objfile,
+ const char *provider,
+ const char *name);
+
+/* Given a PC, find an associated SystemTap probe. If a probe is
+ found, set *OBJFILE_OUT to the probe's objfile, and return the
+ probe. If no probe is found, return NULL. */
+
+extern const struct stap_probe *find_probe_by_pc (CORE_ADDR pc,
+ struct objfile **objfile_out);
+
+/* Given PROBE, this function will parse its arguments and fill the
+ `struct stap_args_info' with proper information about them. */
+
+extern void stap_parse_probe_arguments (struct stap_probe *probe);
+
+/* Given PROBE, returns the number of arguments present in that probe's
+ argument string. */
+
+extern int stap_get_probe_argument_count (const struct stap_probe *probe);
+
+/* Given PARSED_ARGS, frees the space allocated to hold information about
+ the probe's parsed arguments. */
+
+extern void stap_free_parsed_args (struct stap_args_info *parsed_args);
+
+/* Evaluates the probe's argument N, returning a value corresponding
+ to it. */
+
+extern struct value *stap_evaluate_probe_argument (struct objfile *objfile,
+ const struct stap_probe *probe,
+ struct frame_info *frame,
+ int n);
+
+/* Compile the probe's argument N to agent expression. */
+
+extern void stap_compile_to_ax (struct objfile *objfile,
+ const struct stap_probe *probe,
+ struct agent_expr *expr,
+ struct axs_value *value,
+ int n);
+
+/* A convenience function that finds a probe at the PC in FRAME and
+ evaluates argument N. If there is no probe at that location, or if
+ the probe does not have enough arguments, this returns NULL. */
+
+extern struct value *stap_safe_evaluate_at_pc (struct frame_info *frame,
+ int n);
+
+#endif /* !defined (STAP_PROBE_H) */
diff --git a/gdb/symfile.h b/gdb/symfile.h
index a0151ea..752c46a 100644
--- a/gdb/symfile.h
+++ b/gdb/symfile.h
@@ -31,6 +31,11 @@ struct objfile;
struct obj_section;
struct obstack;
struct block;
+struct stap_probe;
+struct value;
+struct frame_info;
+struct agent_expr;
+struct axs_value;
/* Comparison function for symbol look ups. */
@@ -296,6 +301,52 @@ struct quick_symbol_functions
void *data);
};
+/* Structure of functions used for SystemTap probe support. If one of
+ these functions is provided, all must be. */
+
+struct sym_probe_fns
+{
+ /* If non-NULL, return an array of SystemTap probe objects. The
+ number of objects is returned in *NUM_PROBES. */
+ const struct stap_probe *(*sym_get_probes) (struct objfile *,
+ int *num_probes);
+
+ /* Return the number of arguments available to PROBE. PROBE will
+ have come from a call to this objfile's sym_get_probes method.
+ If you provide an implementation of sym_get_probes, you must
+ implement this method as well. */
+ int (*sym_get_probe_argument_count) (struct objfile *objfile,
+ const struct stap_probe *probe);
+
+ /* Evaluate the Nth argument available to PROBE. PROBE will have
+ come from a call to this objfile's sym_get_probes method. N will
+ be between 0 and the number of arguments available to this probe.
+ FRAME is the frame in which the evaluation is done; the frame's
+ PC will match the address of the probe. If you provide an
+ implementation of sym_get_probes, you must implement this method
+ as well. */
+ struct value *(*sym_evaluate_probe_argument) (struct objfile *objfile,
+ const struct stap_probe *probe,
+ struct frame_info *frame,
+ int n);
+
+ /* Compile the Nth probe argument to an agent expression. PROBE
+ will have come from a call to this objfile's sym_get_probes
+ method. N will be between 0 and the number of arguments
+ available to this probe. EXPR and VALUE are the agent expression
+ that is being updated. */
+ void (*sym_compile_to_ax) (struct objfile *objfile,
+ const struct stap_probe *probe,
+ struct agent_expr *expr,
+ struct axs_value *value,
+ int n);
+
+ /* Relocate the probe section of OBJFILE. */
+ void (*sym_relocate_probe) (struct objfile *objfile,
+ struct section_offsets *new_offsets,
+ struct section_offsets *delta);
+};
+
/* Structure to keep track of symbol reading functions for various
object file types. */
@@ -366,6 +417,10 @@ struct sym_fns
bfd_byte *(*sym_relocate) (struct objfile *, asection *sectp, bfd_byte *buf);
+ /* If non-NULL, this objfile has probe support, and all the probe
+ functions referred to here will be non-NULL. */
+ const struct sym_probe_fns *sym_probe_fns;
+
/* The "quick" (aka partial) symbol functions for this symbol
reader. */
const struct quick_symbol_functions *qf;
diff --git a/gdb/symmisc.c b/gdb/symmisc.c
index 4be8106..081b532 100644
--- a/gdb/symmisc.c
+++ b/gdb/symmisc.c
@@ -264,6 +264,9 @@ dump_msymbols (struct objfile *objfile, struct ui_file *outfile)
case mst_text:
ms_type = 'T';
break;
+ case mst_text_gnu_ifunc:
+ ms_type = 'i';
+ break;
case mst_solib_trampoline:
ms_type = 'S';
break;
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 60bc585..734d312 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -770,6 +770,7 @@ init_sal (struct symtab_and_line *sal)
sal->end = 0;
sal->explicit_pc = 0;
sal->explicit_line = 0;
+ sal->semaphore = 0;
}
@@ -3006,7 +3007,7 @@ search_symbols (char *regexp, domain_enum kind, int nfiles, char *files[],
static const enum minimal_symbol_type types3[]
= {mst_file_data, mst_solib_trampoline, mst_abs, mst_unknown};
static const enum minimal_symbol_type types4[]
- = {mst_file_bss, mst_text, mst_abs, mst_unknown};
+ = {mst_file_bss, mst_text_gnu_ifunc, mst_abs, mst_unknown};
enum minimal_symbol_type ourtype;
enum minimal_symbol_type ourtype2;
enum minimal_symbol_type ourtype3;
diff --git a/gdb/symtab.h b/gdb/symtab.h
index e946c65..6239f7f 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -290,6 +290,9 @@ enum minimal_symbol_type
{
mst_unknown = 0, /* Unknown type, the default */
mst_text, /* Generally executable instructions */
+ mst_text_gnu_ifunc, /* Executable code returning address
+ of executable code */
+ mst_slot_got_plt, /* GOT entries for .plt sections */
mst_data, /* Generally initialized data */
mst_bss, /* Generally uninitialized data */
mst_abs, /* Generally absolute (nonrelocatable) */
@@ -953,6 +956,11 @@ extern struct symbol *find_pc_function (CORE_ADDR);
extern struct symbol *find_pc_sect_function (CORE_ADDR, struct obj_section *);
+extern int find_pc_partial_function_gnu_ifunc (CORE_ADDR pc, char **name,
+ CORE_ADDR *address,
+ CORE_ADDR *endaddr,
+ int *is_gnu_ifunc_p);
+
/* lookup function from address, return name, start addr and end addr. */
extern int find_pc_partial_function (CORE_ADDR, char **, CORE_ADDR *,
@@ -1034,6 +1042,35 @@ extern struct minimal_symbol *lookup_minimal_symbol_by_pc_name
extern struct minimal_symbol *lookup_minimal_symbol_by_pc (CORE_ADDR);
+extern int in_gnu_ifunc_stub (CORE_ADDR pc);
+
+/* Functions for resolving STT_GNU_IFUNC symbols which are implemented only
+ for ELF symbol files. */
+
+struct gnu_ifunc_fns
+{
+ /* See elf_gnu_ifunc_resolve_addr for its real implementation. */
+ CORE_ADDR (*gnu_ifunc_resolve_addr) (struct gdbarch *gdbarch, CORE_ADDR pc);
+
+ /* See elf_gnu_ifunc_resolve_name for its real implementation. */
+ int (*gnu_ifunc_resolve_name) (const char *function_name,
+ CORE_ADDR *function_address_p);
+
+ /* See elf_gnu_ifunc_resolver_stop for its real implementation. */
+ void (*gnu_ifunc_resolver_stop) (struct breakpoint *b);
+
+ /* See elf_gnu_ifunc_resolver_return_stop for its real implementation. */
+ void (*gnu_ifunc_resolver_return_stop) (struct breakpoint *b);
+};
+
+#define gnu_ifunc_resolve_addr gnu_ifunc_fns_p->gnu_ifunc_resolve_addr
+#define gnu_ifunc_resolve_name gnu_ifunc_fns_p->gnu_ifunc_resolve_name
+#define gnu_ifunc_resolver_stop gnu_ifunc_fns_p->gnu_ifunc_resolver_stop
+#define gnu_ifunc_resolver_return_stop \
+ gnu_ifunc_fns_p->gnu_ifunc_resolver_return_stop
+
+extern const struct gnu_ifunc_fns *gnu_ifunc_fns_p;
+
extern struct minimal_symbol *
lookup_minimal_symbol_and_objfile (const char *,
struct objfile **);
@@ -1072,6 +1109,10 @@ struct symtab_and_line
CORE_ADDR end;
int explicit_pc;
int explicit_line;
+
+ /* If non-zero, the semaphore location associated with a SystemTap
+ probe. */
+ CORE_ADDR semaphore;
};
extern void init_sal (struct symtab_and_line *sal);
diff --git a/gdb/testsuite/gdb.arch/x86_64-vla-pointer-foo.S b/gdb/testsuite/gdb.arch/x86_64-vla-pointer-foo.S
new file mode 100644
index 0000000..83faaf6
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/x86_64-vla-pointer-foo.S
@@ -0,0 +1,457 @@
+ .file "x86_64-vla-pointer.c"
+ .section .debug_abbrev,"",@progbits
+.Ldebug_abbrev0:
+ .section .debug_info,"",@progbits
+.Ldebug_info0:
+ .section .debug_line,"",@progbits
+.Ldebug_line0:
+ .text
+.Ltext0:
+.globl foo
+ .type foo, @function
+foo:
+.LFB2:
+ .file 1 "x86_64-vla-pointer.c"
+ .loc 1 22 0
+ pushq %rbp
+.LCFI0:
+ movq %rsp, %rbp
+.LCFI1:
+ subq $64, %rsp
+.LCFI2:
+ movl %edi, -36(%rbp)
+ .loc 1 22 0
+ movq %rsp, %rax
+ movq %rax, -48(%rbp)
+ .loc 1 23 0
+ movl -36(%rbp), %edx
+ movslq %edx,%rax
+ subq $1, %rax
+ movq %rax, -24(%rbp)
+ .loc 1 24 0
+ movslq %edx,%rax
+ addq $15, %rax
+ addq $15, %rax
+ shrq $4, %rax
+ salq $4, %rax
+ subq %rax, %rsp
+ movq %rsp, -56(%rbp)
+ movq -56(%rbp), %rax
+ addq $15, %rax
+ shrq $4, %rax
+ salq $4, %rax
+ movq %rax, -56(%rbp)
+ movq -56(%rbp), %rax
+ movq %rax, -16(%rbp)
+ .loc 1 27 0
+ movl $0, -4(%rbp)
+ jmp .L2
+.L3:
+ .loc 1 28 0
+ movl -4(%rbp), %esi
+ movl -4(%rbp), %eax
+ movl %eax, %ecx
+ movq -16(%rbp), %rdx
+ movslq %esi,%rax
+ movb %cl, (%rdx,%rax)
+ .loc 1 27 0
+ addl $1, -4(%rbp)
+.L2:
+ movl -4(%rbp), %eax
+ cmpl -36(%rbp), %eax
+ jl .L3
+ .loc 1 30 0
+ .globl break_here
+break_here:
+ movq -16(%rbp), %rax
+ movb $0, (%rax)
+ movq -48(%rbp), %rsp
+ .loc 1 31 0
+ leave
+ ret
+.LFE2:
+ .size foo, .-foo
+ .section .debug_frame,"",@progbits
+.Lframe0:
+ .long .LECIE0-.LSCIE0
+.LSCIE0:
+ .long 0xffffffff
+ .byte 0x1
+ .string ""
+ .uleb128 0x1
+ .sleb128 -8
+ .byte 0x10
+ .byte 0xc
+ .uleb128 0x7
+ .uleb128 0x8
+ .byte 0x90
+ .uleb128 0x1
+ .align 8
+.LECIE0:
+.LSFDE0:
+ .long .LEFDE0-.LASFDE0
+.LASFDE0:
+ .long .Lframe0
+ .quad .LFB2
+ .quad .LFE2-.LFB2
+ .byte 0x4
+ .long .LCFI0-.LFB2
+ .byte 0xe
+ .uleb128 0x10
+ .byte 0x86
+ .uleb128 0x2
+ .byte 0x4
+ .long .LCFI1-.LCFI0
+ .byte 0xd
+ .uleb128 0x6
+ .align 8
+.LEFDE0:
+ .section .eh_frame,"a",@progbits
+.Lframe1:
+ .long .LECIE1-.LSCIE1
+.LSCIE1:
+ .long 0x0
+ .byte 0x1
+ .string "zR"
+ .uleb128 0x1
+ .sleb128 -8
+ .byte 0x10
+ .uleb128 0x1
+ .byte 0x3
+ .byte 0xc
+ .uleb128 0x7
+ .uleb128 0x8
+ .byte 0x90
+ .uleb128 0x1
+ .align 8
+.LECIE1:
+.LSFDE1:
+ .long .LEFDE1-.LASFDE1
+.LASFDE1:
+ .long .LASFDE1-.Lframe1
+ .long .LFB2
+ .long .LFE2-.LFB2
+ .uleb128 0x0
+ .byte 0x4
+ .long .LCFI0-.LFB2
+ .byte 0xe
+ .uleb128 0x10
+ .byte 0x86
+ .uleb128 0x2
+ .byte 0x4
+ .long .LCFI1-.LCFI0
+ .byte 0xd
+ .uleb128 0x6
+ .align 8
+.LEFDE1:
+ .text
+.Letext0:
+ .section .debug_loc,"",@progbits
+.Ldebug_loc0:
+.LLST0:
+ .quad .LFB2-.Ltext0
+ .quad .LCFI0-.Ltext0
+ .value 0x2
+ .byte 0x77
+ .sleb128 8
+ .quad .LCFI0-.Ltext0
+ .quad .LCFI1-.Ltext0
+ .value 0x2
+ .byte 0x77
+ .sleb128 16
+ .quad .LCFI1-.Ltext0
+ .quad .LFE2-.Ltext0
+ .value 0x2
+ .byte 0x76
+ .sleb128 16
+ .quad 0x0
+ .quad 0x0
+ .section .debug_info
+.Ldebug_relative:
+ .long .Ldebug_end - .Ldebug_start
+.Ldebug_start:
+ .value 0x2
+ .long .Ldebug_abbrev0
+ .byte 0x8
+ .uleb128 0x1
+ .long .LASF2
+ .byte 0x1
+ .long .LASF3
+ .long .LASF4
+ .quad .Ltext0
+ .quad .Letext0
+ .long .Ldebug_line0
+ .uleb128 0x2
+ .byte 0x1
+ .string "foo"
+ .byte 0x1
+ .byte 0x16
+ .byte 0x1
+ .quad .LFB2
+ .quad .LFE2
+ .long .LLST0
+ .long .Ltype_int - .Ldebug_relative
+ .uleb128 0x3
+ .long .LASF5
+ .byte 0x1
+ .byte 0x15
+ .long .Ltype_int - .Ldebug_relative
+ .byte 0x2
+ .byte 0x91
+ .sleb128 -52
+.Ltag_pointer:
+ .uleb128 0x4
+ .byte 0x8 /* DW_AT_byte_size */
+ .long .Ltag_array_type - .debug_info /* DW_AT_type */
+ .uleb128 0x5 /* Abbrev Number: 5 (DW_TAG_variable) */
+ .long .LASF0
+ .byte 0x1
+ .byte 0x18
+#if 1
+ .long .Ltag_pointer - .debug_info
+#else
+ /* Debugging only: Skip the typedef indirection. */
+ .long .Ltag_array_type - .debug_info
+#endif
+ /* DW_AT_location: DW_FORM_block1: start */
+ .byte 0x3
+ .byte 0x91
+ .sleb128 -32
+#if 0
+ .byte 0x6 /* DW_OP_deref */
+#else
+ .byte 0x96 /* DW_OP_nop */
+#endif
+ /* DW_AT_location: DW_FORM_block1: end */
+ .uleb128 0x6
+ .string "i"
+ .byte 0x1
+ .byte 0x19
+ .long .Ltype_int - .Ldebug_relative
+ .byte 0x2
+ .byte 0x91
+ .sleb128 -20
+ .byte 0x0
+.Ltype_int:
+ .uleb128 0x7
+ .byte 0x4
+ .byte 0x5
+ .string "int"
+.Ltag_array_type:
+ .uleb128 0x8 /* Abbrev Number: 8 (DW_TAG_array_type) */
+ .long .Ltype_char - .Ldebug_relative
+ .long .Ltype_ulong - .Ldebug_relative /* DW_AT_sibling: DW_FORM_ref4 */
+1: /* DW_AT_data_location: DW_FORM_block1: start */
+ .byte 2f - 3f /* length */
+3:
+ .byte 0x97 /* DW_OP_push_object_address */
+#if 1
+ .byte 0x6 /* DW_OP_deref */
+#else
+ .byte 0x96 /* DW_OP_nop */
+#endif
+2: /* DW_AT_data_location: DW_FORM_block1: end */
+ .uleb128 0x9
+ .long .Ltype_char - .Ldebug_relative /* DW_AT_type: DW_FORM_ref4 */
+ .byte 0x3
+ .byte 0x91
+ .sleb128 -40
+ .byte 0x6
+ .byte 0x0
+.Ltype_ulong:
+ .uleb128 0xa
+ .byte 0x8
+ .byte 0x7
+.Ltype_char:
+ .uleb128 0xb
+ .byte 0x1
+ .byte 0x6
+ .long .LASF1
+ .byte 0x0
+.Ldebug_end:
+ .section .debug_abbrev
+ .uleb128 0x1
+ .uleb128 0x11
+ .byte 0x1
+ .uleb128 0x25
+ .uleb128 0xe
+ .uleb128 0x13
+ .uleb128 0xb
+ .uleb128 0x3
+ .uleb128 0xe
+ .uleb128 0x1b
+ .uleb128 0xe
+ .uleb128 0x11
+ .uleb128 0x1
+ .uleb128 0x12
+ .uleb128 0x1
+ .uleb128 0x10
+ .uleb128 0x6
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x2
+ .uleb128 0x2e
+ .byte 0x1
+ .uleb128 0x3f
+ .uleb128 0xc
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x27
+ .uleb128 0xc
+ .uleb128 0x11
+ .uleb128 0x1
+ .uleb128 0x12
+ .uleb128 0x1
+ .uleb128 0x40
+ .uleb128 0x6
+ .uleb128 0x1
+ .uleb128 0x13
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x3
+ .uleb128 0x5
+ .byte 0x0
+ .uleb128 0x3
+ .uleb128 0xe
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x2
+ .uleb128 0xa
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x4 /* .Ltag_pointer abbrev */
+ .uleb128 0x0f /* DW_TAG_pointer_type */
+ .byte 0x0
+ .uleb128 0x0b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x5
+ .uleb128 0x34
+ .byte 0x0
+ .uleb128 0x3
+ .uleb128 0xe
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x2
+ .uleb128 0xa
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x6
+ .uleb128 0x34
+ .byte 0x0
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x2
+ .uleb128 0xa
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x7
+ .uleb128 0x24
+ .byte 0x0
+ .uleb128 0xb
+ .uleb128 0xb
+ .uleb128 0x3e
+ .uleb128 0xb
+ .uleb128 0x3
+ .uleb128 0x8
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x8 /* Abbrev Number: 8 (DW_TAG_array_type) */
+ .uleb128 0x1
+ .byte 0x1
+ .uleb128 0x49 /* DW_AT_type */
+ .uleb128 0x13 /* DW_FORM_ref4 */
+ .uleb128 0x1 /* DW_AT_sibling */
+ .uleb128 0x13 /* DW_FORM_ref4 */
+ .uleb128 0x50 /* DW_AT_data_location */
+ .uleb128 0xa /* DW_FORM_block1 */
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x9
+ .uleb128 0x21
+ .byte 0x0
+ .uleb128 0x49 /* DW_AT_type */
+ .uleb128 0x13 /* DW_FORM_ref4 */
+ .uleb128 0x2f
+ .uleb128 0xa
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0xa
+ .uleb128 0x24
+ .byte 0x0
+ .uleb128 0xb
+ .uleb128 0xb
+ .uleb128 0x3e
+ .uleb128 0xb
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0xb
+ .uleb128 0x24
+ .byte 0x0
+ .uleb128 0xb
+ .uleb128 0xb
+ .uleb128 0x3e
+ .uleb128 0xb
+ .uleb128 0x3
+ .uleb128 0xe
+ .byte 0x0
+ .byte 0x0
+ .byte 0x0
+ .section .debug_pubnames,"",@progbits
+ .long 0x16
+ .value 0x2
+ .long .Ldebug_info0
+ .long 0xa8
+ .long 0x2d
+ .string "foo"
+ .long 0x0
+ .section .debug_aranges,"",@progbits
+ .long 0x2c
+ .value 0x2
+ .long .Ldebug_info0
+ .byte 0x8
+ .byte 0x0
+ .value 0x0
+ .value 0x0
+ .quad .Ltext0
+ .quad .Letext0-.Ltext0
+ .quad 0x0
+ .quad 0x0
+ .section .debug_str,"MS",@progbits,1
+.LASF0:
+ .string "array"
+.LASF5:
+ .string "size"
+.LASF3:
+ .string "x86_64-vla-pointer.c"
+.LASF6:
+ .string "array_t"
+.LASF1:
+ .string "char"
+.LASF4:
+ .string "gdb.arch"
+.LASF2:
+ .string "GNU C 4.3.2 20081105 (Red Hat 4.3.2-7)"
+ .ident "GCC: (GNU) 4.3.2 20081105 (Red Hat 4.3.2-7)"
+ .section .note.GNU-stack,"",@progbits
diff --git a/gdb/testsuite/gdb.arch/x86_64-vla-pointer.c b/gdb/testsuite/gdb.arch/x86_64-vla-pointer.c
new file mode 100644
index 0000000..fe2c8f7
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/x86_64-vla-pointer.c
@@ -0,0 +1,43 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2009 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 <http://www.gnu.org/licenses/>. */
+
+#if 0
+
+void
+foo (int size)
+{
+ typedef char array_t[size];
+ array_t array;
+ int i;
+
+ for (i = 0; i < size; i++)
+ array[i] = i;
+
+ array[0] = 0; /* break-here */
+}
+
+#else
+
+int
+main (void)
+{
+ foo (26);
+ foo (78);
+ return 0;
+}
+
+#endif
diff --git a/gdb/testsuite/gdb.arch/x86_64-vla-pointer.exp b/gdb/testsuite/gdb.arch/x86_64-vla-pointer.exp
new file mode 100644
index 0000000..d243cf1
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/x86_64-vla-pointer.exp
@@ -0,0 +1,66 @@
+# Copyright 2009 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 <http://www.gnu.org/licenses/>.
+
+if ![istarget "x86_64-*-*"] then {
+ verbose "Skipping over gdb.arch/x86_64-vla-pointer.exp test made only for x86_64."
+ return
+}
+
+set testfile x86_64-vla-pointer
+set srcasmfile ${testfile}-foo.S
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+set binobjfile ${objdir}/${subdir}/${testfile}-foo.o
+if { [gdb_compile "${srcdir}/${subdir}/${srcasmfile}" "${binobjfile}" object {}] != "" } {
+ untested "Couldn't compile test program"
+ return -1
+}
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile} ${binobjfile}" "${binfile}" executable {debug}] != "" } {
+ untested "Couldn't compile test program"
+ return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+if ![runto_main] {
+ untested x86_64-vla-pointer
+ return -1
+}
+
+gdb_breakpoint "break_here"
+
+gdb_continue_to_breakpoint "break_here"
+
+gdb_test "whatis array" "type = char \\(\\*\\)\\\[variable\\\]" "first: whatis array"
+gdb_test "ptype array" "type = char \\(\\*\\)\\\[26\\\]" "first: ptype array"
+
+gdb_test "whatis *array" "type = char \\\[26\\\]" "first: whatis *array"
+gdb_test "ptype *array" "type = char \\\[26\\\]" "first: ptype *array"
+
+gdb_test "p (*array)\[1\]" "\\$\[0-9\] = 1 '\\\\001'"
+gdb_test "p (*array)\[2\]" "\\$\[0-9\] = 2 '\\\\002'"
+gdb_test "p (*array)\[3\]" "\\$\[0-9\] = 3 '\\\\003'"
+gdb_test "p (*array)\[4\]" "\\$\[0-9\] = 4 '\\\\004'"
+
+gdb_continue_to_breakpoint "break_here"
+
+gdb_test "whatis array" "type = char \\(\\*\\)\\\[variable\\\]" "second: whatis array"
+gdb_test "ptype array" "type = char \\(\\*\\)\\\[78\\\]" "second: ptype array"
+
+gdb_test "whatis *array" "type = char \\\[78\\\]" "second: whatis *array"
+gdb_test "ptype *array" "type = char \\\[78\\\]" "second: ptype *array"
diff --git a/gdb/testsuite/gdb.arch/x86_64-vla-typedef-foo.S b/gdb/testsuite/gdb.arch/x86_64-vla-typedef-foo.S
new file mode 100644
index 0000000..66f7a39
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/x86_64-vla-typedef-foo.S
@@ -0,0 +1,455 @@
+ .file "x86_64-vla-typedef.c"
+ .section .debug_abbrev,"",@progbits
+.Ldebug_abbrev0:
+ .section .debug_info,"",@progbits
+.Ldebug_info0:
+ .section .debug_line,"",@progbits
+.Ldebug_line0:
+ .text
+.Ltext0:
+.globl foo
+ .type foo, @function
+foo:
+.LFB2:
+ .file 1 "x86_64-vla-typedef.c"
+ .loc 1 22 0
+ pushq %rbp
+.LCFI0:
+ movq %rsp, %rbp
+.LCFI1:
+ subq $64, %rsp
+.LCFI2:
+ movl %edi, -36(%rbp)
+ .loc 1 22 0
+ movq %rsp, %rax
+ movq %rax, -48(%rbp)
+ .loc 1 23 0
+ movl -36(%rbp), %edx
+ movslq %edx,%rax
+ subq $1, %rax
+ movq %rax, -24(%rbp)
+ .loc 1 24 0
+ movslq %edx,%rax
+ addq $15, %rax
+ addq $15, %rax
+ shrq $4, %rax
+ salq $4, %rax
+ subq %rax, %rsp
+ movq %rsp, -56(%rbp)
+ movq -56(%rbp), %rax
+ addq $15, %rax
+ shrq $4, %rax
+ salq $4, %rax
+ movq %rax, -56(%rbp)
+ movq -56(%rbp), %rax
+ movq %rax, -16(%rbp)
+ .loc 1 27 0
+ movl $0, -4(%rbp)
+ jmp .L2
+.L3:
+ .loc 1 28 0
+ movl -4(%rbp), %esi
+ movl -4(%rbp), %eax
+ movl %eax, %ecx
+ movq -16(%rbp), %rdx
+ movslq %esi,%rax
+ movb %cl, (%rdx,%rax)
+ .loc 1 27 0
+ addl $1, -4(%rbp)
+.L2:
+ movl -4(%rbp), %eax
+ cmpl -36(%rbp), %eax
+ jl .L3
+ .loc 1 30 0
+ .globl break_here
+break_here:
+ movq -16(%rbp), %rax
+ movb $0, (%rax)
+ movq -48(%rbp), %rsp
+ .loc 1 31 0
+ leave
+ ret
+.LFE2:
+ .size foo, .-foo
+ .section .debug_frame,"",@progbits
+.Lframe0:
+ .long .LECIE0-.LSCIE0
+.LSCIE0:
+ .long 0xffffffff
+ .byte 0x1
+ .string ""
+ .uleb128 0x1
+ .sleb128 -8
+ .byte 0x10
+ .byte 0xc
+ .uleb128 0x7
+ .uleb128 0x8
+ .byte 0x90
+ .uleb128 0x1
+ .align 8
+.LECIE0:
+.LSFDE0:
+ .long .LEFDE0-.LASFDE0
+.LASFDE0:
+ .long .Lframe0
+ .quad .LFB2
+ .quad .LFE2-.LFB2
+ .byte 0x4
+ .long .LCFI0-.LFB2
+ .byte 0xe
+ .uleb128 0x10
+ .byte 0x86
+ .uleb128 0x2
+ .byte 0x4
+ .long .LCFI1-.LCFI0
+ .byte 0xd
+ .uleb128 0x6
+ .align 8
+.LEFDE0:
+ .section .eh_frame,"a",@progbits
+.Lframe1:
+ .long .LECIE1-.LSCIE1
+.LSCIE1:
+ .long 0x0
+ .byte 0x1
+ .string "zR"
+ .uleb128 0x1
+ .sleb128 -8
+ .byte 0x10
+ .uleb128 0x1
+ .byte 0x3
+ .byte 0xc
+ .uleb128 0x7
+ .uleb128 0x8
+ .byte 0x90
+ .uleb128 0x1
+ .align 8
+.LECIE1:
+.LSFDE1:
+ .long .LEFDE1-.LASFDE1
+.LASFDE1:
+ .long .LASFDE1-.Lframe1
+ .long .LFB2
+ .long .LFE2-.LFB2
+ .uleb128 0x0
+ .byte 0x4
+ .long .LCFI0-.LFB2
+ .byte 0xe
+ .uleb128 0x10
+ .byte 0x86
+ .uleb128 0x2
+ .byte 0x4
+ .long .LCFI1-.LCFI0
+ .byte 0xd
+ .uleb128 0x6
+ .align 8
+.LEFDE1:
+ .text
+.Letext0:
+ .section .debug_loc,"",@progbits
+.Ldebug_loc0:
+.LLST0:
+ .quad .LFB2-.Ltext0
+ .quad .LCFI0-.Ltext0
+ .value 0x2
+ .byte 0x77
+ .sleb128 8
+ .quad .LCFI0-.Ltext0
+ .quad .LCFI1-.Ltext0
+ .value 0x2
+ .byte 0x77
+ .sleb128 16
+ .quad .LCFI1-.Ltext0
+ .quad .LFE2-.Ltext0
+ .value 0x2
+ .byte 0x76
+ .sleb128 16
+ .quad 0x0
+ .quad 0x0
+ .section .debug_info
+ .long .Ldebug_end - .Ldebug_start
+.Ldebug_start:
+ .value 0x2
+ .long .Ldebug_abbrev0
+ .byte 0x8
+ .uleb128 0x1
+ .long .LASF2
+ .byte 0x1
+ .long .LASF3
+ .long .LASF4
+ .quad .Ltext0
+ .quad .Letext0
+ .long .Ldebug_line0
+ .uleb128 0x2
+ .byte 0x1
+ .string "foo"
+ .byte 0x1
+ .byte 0x16
+ .byte 0x1
+ .quad .LFB2
+ .quad .LFE2
+ .long .LLST0
+ .long 0x83
+ .uleb128 0x3
+ .long .LASF5
+ .byte 0x1
+ .byte 0x15
+ .long 0x83
+ .byte 0x2
+ .byte 0x91
+ .sleb128 -52
+.Ltag_typedef:
+ .uleb128 0x4
+ .long .LASF6
+ .byte 0x1
+ .byte 0x17
+ .long .Ltag_array_type - .debug_info
+ .uleb128 0x5 /* Abbrev Number: 5 (DW_TAG_variable) */
+ .long .LASF0
+ .byte 0x1
+ .byte 0x18
+#if 1
+ .long .Ltag_typedef - .debug_info
+#else
+ /* Debugging only: Skip the typedef indirection. */
+ .long .Ltag_array_type - .debug_info
+#endif
+ /* DW_AT_location: DW_FORM_block1: start */
+ .byte 0x3
+ .byte 0x91
+ .sleb128 -32
+#if 0
+ .byte 0x6 /* DW_OP_deref */
+#else
+ .byte 0x96 /* DW_OP_nop */
+#endif
+ /* DW_AT_location: DW_FORM_block1: end */
+ .uleb128 0x6
+ .string "i"
+ .byte 0x1
+ .byte 0x19
+ .long 0x83
+ .byte 0x2
+ .byte 0x91
+ .sleb128 -20
+ .byte 0x0
+ .uleb128 0x7
+ .byte 0x4
+ .byte 0x5
+ .string "int"
+.Ltag_array_type:
+ .uleb128 0x8 /* Abbrev Number: 8 (DW_TAG_array_type) */
+ .long 0xa0 + (2f - 1f) /* DW_AT_type: DW_FORM_ref4 */
+ .long 0x9d + (2f - 1f) /* DW_AT_sibling: DW_FORM_ref4 */
+1: /* DW_AT_data_location: DW_FORM_block1: start */
+ .byte 2f - 3f /* length */
+3:
+ .byte 0x97 /* DW_OP_push_object_address */
+ .byte 0x6 /* DW_OP_deref */
+2: /* DW_AT_data_location: DW_FORM_block1: end */
+ .uleb128 0x9
+ .long 0x9d + (2b - 1b) /* DW_AT_type: DW_FORM_ref4 */
+ .byte 0x3
+ .byte 0x91
+ .sleb128 -40
+ .byte 0x6
+ .byte 0x0
+ .uleb128 0xa
+ .byte 0x8
+ .byte 0x7
+ .uleb128 0xb
+ .byte 0x1
+ .byte 0x6
+ .long .LASF1
+ .byte 0x0
+.Ldebug_end:
+ .section .debug_abbrev
+ .uleb128 0x1
+ .uleb128 0x11
+ .byte 0x1
+ .uleb128 0x25
+ .uleb128 0xe
+ .uleb128 0x13
+ .uleb128 0xb
+ .uleb128 0x3
+ .uleb128 0xe
+ .uleb128 0x1b
+ .uleb128 0xe
+ .uleb128 0x11
+ .uleb128 0x1
+ .uleb128 0x12
+ .uleb128 0x1
+ .uleb128 0x10
+ .uleb128 0x6
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x2
+ .uleb128 0x2e
+ .byte 0x1
+ .uleb128 0x3f
+ .uleb128 0xc
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x27
+ .uleb128 0xc
+ .uleb128 0x11
+ .uleb128 0x1
+ .uleb128 0x12
+ .uleb128 0x1
+ .uleb128 0x40
+ .uleb128 0x6
+ .uleb128 0x1
+ .uleb128 0x13
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x3
+ .uleb128 0x5
+ .byte 0x0
+ .uleb128 0x3
+ .uleb128 0xe
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x2
+ .uleb128 0xa
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x4
+ .uleb128 0x16
+ .byte 0x0
+ .uleb128 0x3
+ .uleb128 0xe
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x5
+ .uleb128 0x34
+ .byte 0x0
+ .uleb128 0x3
+ .uleb128 0xe
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x2
+ .uleb128 0xa
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x6
+ .uleb128 0x34
+ .byte 0x0
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x2
+ .uleb128 0xa
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x7
+ .uleb128 0x24
+ .byte 0x0
+ .uleb128 0xb
+ .uleb128 0xb
+ .uleb128 0x3e
+ .uleb128 0xb
+ .uleb128 0x3
+ .uleb128 0x8
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x8 /* Abbrev Number: 8 (DW_TAG_array_type) */
+ .uleb128 0x1
+ .byte 0x1
+ .uleb128 0x49 /* DW_AT_type */
+ .uleb128 0x13 /* DW_FORM_ref4 */
+ .uleb128 0x1 /* DW_AT_sibling */
+ .uleb128 0x13 /* DW_FORM_ref4 */
+ .uleb128 0x50 /* DW_AT_data_location */
+ .uleb128 0xa /* DW_FORM_block1 */
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x9
+ .uleb128 0x21
+ .byte 0x0
+ .uleb128 0x49 /* DW_AT_type */
+ .uleb128 0x13 /* DW_FORM_ref4 */
+ .uleb128 0x2f
+ .uleb128 0xa
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0xa
+ .uleb128 0x24
+ .byte 0x0
+ .uleb128 0xb
+ .uleb128 0xb
+ .uleb128 0x3e
+ .uleb128 0xb
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0xb
+ .uleb128 0x24
+ .byte 0x0
+ .uleb128 0xb
+ .uleb128 0xb
+ .uleb128 0x3e
+ .uleb128 0xb
+ .uleb128 0x3
+ .uleb128 0xe
+ .byte 0x0
+ .byte 0x0
+ .byte 0x0
+ .section .debug_pubnames,"",@progbits
+ .long 0x16
+ .value 0x2
+ .long .Ldebug_info0
+ .long 0xa8
+ .long 0x2d
+ .string "foo"
+ .long 0x0
+ .section .debug_aranges,"",@progbits
+ .long 0x2c
+ .value 0x2
+ .long .Ldebug_info0
+ .byte 0x8
+ .byte 0x0
+ .value 0x0
+ .value 0x0
+ .quad .Ltext0
+ .quad .Letext0-.Ltext0
+ .quad 0x0
+ .quad 0x0
+ .section .debug_str,"MS",@progbits,1
+.LASF0:
+ .string "array"
+.LASF5:
+ .string "size"
+.LASF3:
+ .string "x86_64-vla-typedef.c"
+.LASF6:
+ .string "array_t"
+.LASF1:
+ .string "char"
+.LASF4:
+ .string "gdb.arch"
+.LASF2:
+ .string "GNU C 4.3.2 20081105 (Red Hat 4.3.2-7)"
+ .ident "GCC: (GNU) 4.3.2 20081105 (Red Hat 4.3.2-7)"
+ .section .note.GNU-stack,"",@progbits
diff --git a/gdb/testsuite/gdb.arch/x86_64-vla-typedef.c b/gdb/testsuite/gdb.arch/x86_64-vla-typedef.c
new file mode 100644
index 0000000..b809c4e
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/x86_64-vla-typedef.c
@@ -0,0 +1,43 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2008 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 <http://www.gnu.org/licenses/>. */
+
+#if 0
+
+void
+foo (int size)
+{
+ typedef char array_t[size];
+ array_t array;
+ int i;
+
+ for (i = 0; i < size; i++)
+ array[i] = i;
+
+ array[0] = 0; /* break-here */
+}
+
+#else
+
+int
+main (void)
+{
+ foo (26);
+ foo (78);
+ return 0;
+}
+
+#endif
diff --git a/gdb/testsuite/gdb.arch/x86_64-vla-typedef.exp b/gdb/testsuite/gdb.arch/x86_64-vla-typedef.exp
new file mode 100644
index 0000000..b05411e
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/x86_64-vla-typedef.exp
@@ -0,0 +1,64 @@
+# Copyright 2009 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 <http://www.gnu.org/licenses/>.
+
+# Test DW_AT_data_location accessed through DW_TAG_typedef intermediate.
+
+if ![istarget "x86_64-*-*"] then {
+ verbose "Skipping over gdb.arch/x86_64-vla-typedef.exp test made only for x86_64."
+ return
+}
+
+set testfile x86_64-vla-typedef
+set srcasmfile ${testfile}-foo.S
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+set binobjfile ${objdir}/${subdir}/${testfile}-foo.o
+if { [gdb_compile "${srcdir}/${subdir}/${srcasmfile}" "${binobjfile}" object {}] != "" } {
+ untested "Couldn't compile test program"
+ return -1
+}
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile} ${binobjfile}" "${binfile}" executable {debug}] != "" } {
+ untested "Couldn't compile test program"
+ return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+if ![runto_main] {
+ untested x86_64-vla-typedef
+ return -1
+}
+
+gdb_breakpoint "break_here"
+
+gdb_continue_to_breakpoint "break_here"
+
+gdb_test "whatis array" "type = array_t" "first: whatis array"
+
+gdb_test "ptype array" "type = char \\\[26\\\]" "first: ptype array"
+
+gdb_test "p array\[1\]" "\\$\[0-9\] = 1 '\\\\001'"
+gdb_test "p array\[2\]" "\\$\[0-9\] = 2 '\\\\002'"
+gdb_test "p array\[3\]" "\\$\[0-9\] = 3 '\\\\003'"
+gdb_test "p array\[4\]" "\\$\[0-9\] = 4 '\\\\004'"
+
+gdb_continue_to_breakpoint "break_here"
+
+gdb_test "whatis array" "type = array_t" "second: whatis array"
+
+gdb_test "ptype array" "type = char \\\[78\\\]" "second: ptype array"
diff --git a/gdb/testsuite/gdb.base/arrayidx.c b/gdb/testsuite/gdb.base/arrayidx.c
index 6c158bf..739ce34 100644
--- a/gdb/testsuite/gdb.base/arrayidx.c
+++ b/gdb/testsuite/gdb.base/arrayidx.c
@@ -17,6 +17,13 @@
int array[] = {1, 2, 3, 4};
+#ifdef __GNUC__
+struct
+ {
+ int a[0];
+ } unbound;
+#endif
+
int
main (void)
{
diff --git a/gdb/testsuite/gdb.base/arrayidx.exp b/gdb/testsuite/gdb.base/arrayidx.exp
index d8ee5c0..de4ba75 100644
--- a/gdb/testsuite/gdb.base/arrayidx.exp
+++ b/gdb/testsuite/gdb.base/arrayidx.exp
@@ -57,4 +57,12 @@ gdb_test "print array" \
"\\{\\\[0\\\] = 1, \\\[1\\\] = 2, \\\[2\\\] = 3, \\\[3\\\] = 4\\}" \
"Print array with array-indexes on"
-
+set test "p unbound.a == &unbound.a\[0\]"
+gdb_test_multiple $test $test {
+ -re " = 1\r\n$gdb_prompt $" {
+ pass $test
+ }
+ -re "No symbol \"unbound\" in current context.\r\n$gdb_prompt $" {
+ unsupported "$test (no GCC)"
+ }
+}
diff --git a/gdb/testsuite/gdb.base/gnu-ifunc-lib.c b/gdb/testsuite/gdb.base/gnu-ifunc-lib.c
new file mode 100644
index 0000000..dc6710e
--- /dev/null
+++ b/gdb/testsuite/gdb.base/gnu-ifunc-lib.c
@@ -0,0 +1,33 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2009, 2010, 2011 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 <http://www.gnu.org/licenses/>. */
+
+extern volatile int gnu_ifunc_initialized;
+extern int init_stub (int arg);
+extern int final (int arg);
+
+typedef int (*final_t) (int arg);
+
+asm (".type gnu_ifunc, @gnu_indirect_function");
+
+final_t
+gnu_ifunc (void)
+{
+ if (! gnu_ifunc_initialized)
+ return init_stub;
+ else
+ return final;
+}
diff --git a/gdb/testsuite/gdb.base/gnu-ifunc.c b/gdb/testsuite/gdb.base/gnu-ifunc.c
new file mode 100644
index 0000000..0ee741f
--- /dev/null
+++ b/gdb/testsuite/gdb.base/gnu-ifunc.c
@@ -0,0 +1,61 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2009, 2010, 2011 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 <http://www.gnu.org/licenses/>. */
+
+#include <assert.h>
+
+int
+init_stub (int arg)
+{
+ return 0;
+}
+
+int
+final (int arg)
+{
+ return arg + 1;
+}
+
+/* Make differentiation of how the gnu_ifunc call resolves before and after
+ calling gnu_ifunc_pre. This ensures the resolved function address is not
+ being cached anywhere for the debugging purposes. */
+
+volatile int gnu_ifunc_initialized;
+
+static void
+gnu_ifunc_pre (void)
+{
+ assert (!gnu_ifunc_initialized);
+
+ gnu_ifunc_initialized = 1;
+}
+
+extern int gnu_ifunc (int arg);
+
+int
+main (void)
+{
+ int i;
+
+ gnu_ifunc_pre ();
+
+ i = gnu_ifunc (1); /* break-at-call */
+ assert (i == 2);
+
+ gnu_ifunc (2); /* break-at-nextcall */
+
+ return 0; /* break-at-exit */
+}
diff --git a/gdb/testsuite/gdb.base/gnu-ifunc.exp b/gdb/testsuite/gdb.base/gnu-ifunc.exp
new file mode 100644
index 0000000..4fcc3bf
--- /dev/null
+++ b/gdb/testsuite/gdb.base/gnu-ifunc.exp
@@ -0,0 +1,146 @@
+# Copyright (C) 2009, 2010, 2011 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 <http://www.gnu.org/licenses/>.
+
+if {[skip_shlib_tests]} {
+ return 0
+}
+
+set testfile "gnu-ifunc"
+set executable ${testfile}
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${executable}
+set staticexecutable ${executable}-static
+set staticbinfile ${objdir}/${subdir}/${staticexecutable}
+
+set libfile "${testfile}-lib"
+set libsrc ${libfile}.c
+set lib_so ${objdir}/${subdir}/${libfile}.so
+# $lib_o must not have {debug}, it would override the STT_GNU_IFUNC ELF markers.
+set lib_o ${objdir}/${subdir}/${libfile}.o
+
+# We need DWARF for the "final" function as we "step" into the function and GDB
+# would step-over the "final" function if there would be no line number debug
+# information (DWARF) available.
+#
+# We must not have DWARF for the "gnu_ifunc" function as DWARF has no way to
+# express the STT_GNU_IFUNC type and it would be considered as a regular
+# function due to DWARF by GDB. In ELF gnu-ifunc is expressed by the
+# STT_GNU_IFUNC type.
+#
+# Both functions need to be in the same shared library file but
+# gdb_compile_shlib has no way to specify source-specific compilation options.
+#
+# Therefore $libfile contains only the STT_GNU_IFUNC function with no DWARF
+# referencing all the other parts from the main executable with DWARF.
+
+set lib_opts {}
+set exec_opts [list debug shlib=$lib_so]
+
+if [get_compiler_info ${binfile}] {
+ return -1
+}
+
+if { [gdb_compile_shlib ${srcdir}/${subdir}/$libsrc $lib_so $lib_opts] != ""
+ || [gdb_compile ${srcdir}/${subdir}/$srcfile $binfile executable $exec_opts] != ""} {
+ untested "Could not compile dynamic executable $binfile."
+ return -1
+}
+
+# Start with a fresh gdb.
+
+clean_restart $executable
+gdb_load_shlibs ${lib_so}
+
+if ![runto_main] then {
+ fail "Can't run to main"
+ return 1;
+}
+
+# The "if" condition is artifical to test regression of a former patch.
+gdb_breakpoint "[gdb_get_line_number "break-at-nextcall"] if i && gnu_ifunc (i) != 42"
+
+gdb_breakpoint [gdb_get_line_number "break-at-call"]
+gdb_continue_to_breakpoint "break-at-call" ".*break-at-call.*"
+
+# Test GDB will automatically indirect the call.
+
+gdb_test "p gnu_ifunc (3)" " = 4"
+
+# Test GDB will skip the gnu_ifunc resolver on first call.
+
+gdb_test "step" "\r\nfinal .*"
+
+# Test GDB will not break before the final chosen implementation.
+
+# Also test a former patch regression:
+# Continuing.
+# Error in testing breakpoint condition:
+# Attempt to take address of value not located in memory.
+#
+# Breakpoint 2, main () at ./gdb.base/gnu-ifunc.c:33
+
+gdb_test "continue" "Continuing.\r\n\r\nBreakpoint .* (at|in) .*break-at-nextcall.*" \
+ "continue to break-at-nextcall"
+
+gdb_breakpoint "gnu_ifunc"
+
+gdb_continue_to_breakpoint "nextcall gnu_ifunc"
+
+gdb_test "frame" "#0 +(0x\[0-9a-f\]+ in +)?final \\(.*" "nextcall gnu_ifunc skipped"
+
+
+# Check any commands not doing an inferior call access the address of the
+# STT_GNU_IFUNC resolver, not the target function.
+
+if {[istarget powerpc64-*] && [is_lp64_target]} {
+ # With only minimal symbols GDB provides the function descriptors. With
+ # full debug info the function code would be displayed.
+ set func_prefix {\.}
+} else {
+ set func_prefix {}
+}
+
+gdb_test "p gnu_ifunc" " = {<text gnu-indirect-function variable, no debug info>} 0x\[0-9a-f\]+ <${func_prefix}gnu_ifunc>" "p gnu_ifunc executing"
+gdb_test "info sym gnu_ifunc" "gnu_ifunc in section .*" "info sym gnu_ifunc executing"
+
+set test "info addr gnu_ifunc"
+gdb_test_multiple $test $test {
+ -re "Symbol \"gnu_ifunc\" is at (0x\[0-9a-f\]+) in .*$gdb_prompt $" {
+ pass $test
+ }
+}
+gdb_test "info sym $expect_out(1,string)" "gnu_ifunc in section .*" "info sym <gnu_ifunc-address>"
+
+
+# Test statically linked ifunc resolving during inferior start.
+# https://bugzilla.redhat.com/show_bug.cgi?id=624967
+
+if ![target_info exists gdb_stub] {
+
+ # Compile $staticbinfile separately as it may exit on error (ld/12595).
+
+ if { [gdb_compile ${srcdir}/${subdir}/$libsrc $lib_o object {}] != ""
+ || [gdb_compile "${srcdir}/${subdir}/$srcfile $lib_o" $staticbinfile executable {debug}] != "" } {
+ untested "Could not compile static executable $staticbinfile."
+ return -1
+ }
+
+ clean_restart $staticexecutable
+
+ gdb_breakpoint "gnu_ifunc"
+ gdb_breakpoint "main"
+ gdb_run_cmd
+ gdb_test "" "Breakpoint \[0-9\]*, main .*" "static gnu_ifunc"
+}
diff --git a/gdb/testsuite/gdb.base/internal-var-field-address.c b/gdb/testsuite/gdb.base/internal-var-field-address.c
new file mode 100644
index 0000000..eeb7b85
--- /dev/null
+++ b/gdb/testsuite/gdb.base/internal-var-field-address.c
@@ -0,0 +1,20 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2009 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 <http://www.gnu.org/licenses/>. */
+
+struct {
+ int field;
+} staticstruct = { 1 };
diff --git a/gdb/testsuite/gdb.base/internal-var-field-address.exp b/gdb/testsuite/gdb.base/internal-var-field-address.exp
new file mode 100644
index 0000000..6d82e73
--- /dev/null
+++ b/gdb/testsuite/gdb.base/internal-var-field-address.exp
@@ -0,0 +1,26 @@
+# Copyright 2009 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 <http://www.gnu.org/licenses/>.
+
+set test internal-var-field-address
+set binfile ${test}.x
+if { [gdb_compile "${srcdir}/${subdir}/${test}.c" "${objdir}/${subdir}/${binfile}" object {debug}] != "" } {
+ untested "Couldn't compile test program"
+ return -1
+}
+
+clean_restart $binfile
+
+gdb_test {set $varstruct = staticstruct}
+gdb_test {p $varstruct.field} " = 1"
diff --git a/gdb/testsuite/gdb.base/stap-probe.c b/gdb/testsuite/gdb.base/stap-probe.c
new file mode 100644
index 0000000..47e4b39
--- /dev/null
+++ b/gdb/testsuite/gdb.base/stap-probe.c
@@ -0,0 +1,69 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2011 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 <http://www.gnu.org/licenses/>. */
+
+#if USE_PROBES
+
+#define _SDT_HAS_SEMAPHORES
+__extension__ unsigned short teste_user_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes")));
+#define TEST teste_user_semaphore
+
+__extension__ unsigned short teste_two_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes")));
+#define TEST2 teste_two_semaphore
+
+#else
+
+#define TEST 1
+#define TEST2 1
+
+#endif
+
+#include <sys/sdt.h>
+
+/* We only support SystemTap and only the v3 form. */
+#if _SDT_NOTE_TYPE != 3
+#error "not using SystemTap v3 probes"
+#endif
+
+void
+m1 (void)
+{
+ if (TEST2)
+ STAP_PROBE (teste, two);
+}
+
+void
+m2 (void)
+{
+ if (TEST2)
+ STAP_PROBE (teste, two);
+}
+
+int
+f (int x)
+{
+ if (TEST)
+ STAP_PROBE1(teste, user, x);
+ return x+5;
+}
+
+int
+main()
+{
+ f(f(23));
+ m1();
+ m2();
+}
diff --git a/gdb/testsuite/gdb.base/stap-probe.exp b/gdb/testsuite/gdb.base/stap-probe.exp
new file mode 100644
index 0000000..bc3d40c
--- /dev/null
+++ b/gdb/testsuite/gdb.base/stap-probe.exp
@@ -0,0 +1,72 @@
+# Copyright (C) 2011 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 <http://www.gnu.org/licenses/>.
+
+set testfile stap-probe
+
+# Run the tests. We run the tests two different ways: once with a
+# plain probe, and once with a probe that has an associated semaphore.
+# This returns -1 on failure to compile or start, 0 otherwise.
+proc stap_test {{arg ""}} {
+ global testfile hex
+
+ if {$arg != ""} {
+ set arg "additional_flags=$arg"
+ set addendum ", with semaphore"
+ } else {
+ set addendum ", no semaphore"
+ }
+
+ if {[prepare_for_testing ${testfile}.exp ${testfile} ${testfile}.c \
+ [concat $arg debug]]} {
+ return -1
+ }
+
+ if ![runto_main] {
+ return -1
+ }
+
+ gdb_test "print \$_probe_argc" "No SystemTap probe at PC $hex" \
+ "check argument not at probe point$addendum"
+
+ gdb_test "info probes" \
+ "teste *user *$hex .*" \
+ "info probes$addendum"
+
+ if {[runto "probe:teste:user"]} {
+ pass "run to probe:teste:user$addendum"
+ } else {
+ fail "run to probe:teste:user$addendum"
+ }
+
+ # Test probe arguments.
+ gdb_test "print \$_probe_argc" " = 1" "print \$_probe_argc$addendum"
+ gdb_test "print \$_probe_arg0 == x" " = 1" "check \$_probe_arg0$addendum"
+ gdb_test "print \$_probe_arg1" \
+ "Invalid probe argument 1 -- probe has 1 arguments available" \
+ "check \$_probe_arg1$addendum"
+
+ # Set a breakpoint with multiple probe locations.
+ gdb_test "break probe:teste:two" \
+ "Breakpoint .* at $hex.*Breakpoint .* at $hex.*" \
+ "set multi-location probe breakpoint$addendum"
+
+ return 0
+}
+
+if {[stap_test] == -1} {
+ untested stap-probe.exp
+ return -1
+}
+stap_test "-DUSE_PROBES"
diff --git a/gdb/testsuite/gdb.base/vla-overflow.c b/gdb/testsuite/gdb.base/vla-overflow.c
new file mode 100644
index 0000000..c5d5ee0
--- /dev/null
+++ b/gdb/testsuite/gdb.base/vla-overflow.c
@@ -0,0 +1,30 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2008 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 <http://www.gnu.org/licenses/>. */
+
+#include <stdlib.h>
+
+int
+main (int argc, char **argv)
+{
+ int array[argc];
+
+ array[0] = array[0];
+
+ abort ();
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.base/vla-overflow.exp b/gdb/testsuite/gdb.base/vla-overflow.exp
new file mode 100644
index 0000000..24a608f
--- /dev/null
+++ b/gdb/testsuite/gdb.base/vla-overflow.exp
@@ -0,0 +1,109 @@
+# Copyright 2008 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 <http://www.gnu.org/licenses/>.
+
+# We could crash in:
+# #0 block_linkage_function (bl=0x0) at ../../gdb/block.c:69
+# #1 in dwarf_block_get_frame_base (...) at ../../gdb/dwarf2block.c:97
+# 97 framefunc = block_linkage_function (get_frame_block (frame, NULL));
+# #2 in execute_stack_op (...) at ../../gdb/dwarf2expr.c:496
+# #3 in dwarf_block_exec_core () at ../../gdb/dwarf2block.c:156
+# #4 dwarf_block_exec (...) at ../../gdb/dwarf2block.c:206
+# #5 in range_type_count_bound_internal (...) at ../../gdb/gdbtypes.c:1430
+# #6 in create_array_type (...) at ../../gdb/gdbtypes.c:840
+# ...
+# #21 in psymtab_to_symtab (...) at ../../gdb/symfile.c:292
+# ...
+# #29 in backtrace_command_1 () at ../../gdb/stack.c:1273
+
+set testfile vla-overflow
+set shfile ${objdir}/${subdir}/${testfile}-gdb.sh
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+ untested "Couldn't compile test program"
+ return -1
+}
+
+set f [open "|getconf PAGESIZE" "r"]
+gets $f pagesize
+close $f
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+set pid_of_gdb [exp_pid -i [board_info host fileid]]
+
+if { [runto_main] < 0 } {
+ untested vla-overflow
+ return -1
+}
+
+# Get the GDB memory size when we stay at main.
+
+proc memory_v_pages_get {} {
+ global pid_of_gdb pagesize
+ set fd [open "/proc/$pid_of_gdb/statm"]
+ gets $fd line
+ close $fd
+ # number of pages of virtual memory
+ scan $line "%d" drs
+ return $drs
+}
+
+set pages_found [memory_v_pages_get]
+
+# s390x with glibc-debuginfo.s390x installed used approx. 16MB.
+set mb_reserve 40
+verbose -log "pages_found = $pages_found, mb_reserve = $mb_reserve"
+set kb_found [expr $pages_found * $pagesize / 1024]
+set kb_permit [expr $kb_found + 1 * 1024 + $mb_reserve * 1024]
+verbose -log "kb_found = $kb_found, kb_permit = $kb_permit"
+
+# Create the ulimit wrapper.
+set f [open $shfile "w"]
+puts $f "#! /bin/sh"
+puts $f "ulimit -v $kb_permit"
+puts $f "exec $GDB \"\$@\""
+close $f
+remote_exec host "chmod +x $shfile"
+
+gdb_exit
+set GDBold $GDB
+set GDB "$shfile"
+gdb_start
+set GDB $GDBold
+
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+set pid_of_gdb [exp_pid -i [board_info host fileid]]
+
+# Check the size again after the second run.
+# We must not stop in main as it would cache `array' and never crash later.
+
+gdb_run_cmd
+
+verbose -log "kb_found before abort() = [expr [memory_v_pages_get] * $pagesize / 1024]"
+
+gdb_test "" "Program received signal SIGABRT, Aborted..*" "Enter abort()"
+
+verbose -log "kb_found in abort() = [expr [memory_v_pages_get] * $pagesize / 1024]"
+
+# `abort' can get expressed as `*__GI_abort'.
+gdb_test "bt" "in \[^ \]*abort \\(.* in main \\(.*" "Backtrace after abort()"
+
+verbose -log "kb_found in bt after abort() = [expr [memory_v_pages_get] * $pagesize / 1024]"
diff --git a/gdb/testsuite/gdb.base/vla.c b/gdb/testsuite/gdb.base/vla.c
new file mode 100644
index 0000000..e1f3ed1
--- /dev/null
+++ b/gdb/testsuite/gdb.base/vla.c
@@ -0,0 +1,55 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2008 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 <http://www.gnu.org/licenses/>. */
+
+#include <string.h>
+
+void
+marker (void)
+{
+}
+
+void
+bar (char *a, char *b, char *c, int size)
+{
+ memset (a, '1', size);
+ memset (b, '2', size);
+ memset (c, '3', 48);
+}
+
+void
+foo (int size)
+{
+ char temp1[size];
+ char temp3[48];
+
+ temp1[size - 1] = '\0';
+ {
+ char temp2[size];
+
+ bar (temp1, temp2, temp3, size);
+
+ marker (); /* break-here */
+ }
+}
+
+int
+main (void)
+{
+ foo (26);
+ foo (78);
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.base/vla.exp b/gdb/testsuite/gdb.base/vla.exp
new file mode 100644
index 0000000..5da7378
--- /dev/null
+++ b/gdb/testsuite/gdb.base/vla.exp
@@ -0,0 +1,62 @@
+# Copyright 2008 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 <http://www.gnu.org/licenses/>.
+
+set testfile vla
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+ untested "Couldn't compile test program"
+ return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+if ![runto_main] {
+ untested vla
+ return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "break-here"]
+
+gdb_continue_to_breakpoint "break-here"
+
+gdb_test "whatis temp1" "type = char \\\[variable\\\]" "first: whatis temp1"
+gdb_test "whatis temp2" "type = char \\\[variable\\\]" "first: whatis temp2"
+gdb_test "whatis temp3" "type = char \\\[48\\\]" "first: whatis temp3"
+
+gdb_test "ptype temp1" "type = char \\\[26\\\]" "first: ptype temp1"
+gdb_test "ptype temp2" "type = char \\\[26\\\]" "first: ptype temp2"
+gdb_test "ptype temp3" "type = char \\\[48\\\]" "first: ptype temp3"
+
+gdb_test "p temp1" " = '1' <repeats 26 times>" "first: print temp1"
+gdb_test "p temp2" " = '2' <repeats 26 times>" "first: print temp2"
+gdb_test "p temp3" " = '3' <repeats 48 times>" "first: print temp3"
+
+gdb_continue_to_breakpoint "break-here"
+
+gdb_test "whatis temp1" "type = char \\\[variable\\\]" "second: whatis temp1"
+gdb_test "whatis temp2" "type = char \\\[variable\\\]" "second: whatis temp2"
+gdb_test "whatis temp3" "type = char \\\[48\\\]" "second: whatis temp3"
+
+gdb_test "ptype temp1" "type = char \\\[78\\\]" "second: ptype temp1"
+gdb_test "ptype temp2" "type = char \\\[78\\\]" "second: ptype temp2"
+gdb_test "ptype temp3" "type = char \\\[48\\\]" "second: ptype temp3"
+
+gdb_test "p temp1" " = '1' <repeats 78 times>" "second: print temp1"
+gdb_test "p temp2" " = '2' <repeats 78 times>" "second: print temp2"
+gdb_test "p temp3" " = '3' <repeats 48 times>" "second: print temp3"
diff --git a/gdb/testsuite/gdb.base/watchpoint-delete.c b/gdb/testsuite/gdb.base/watchpoint-delete.c
new file mode 100644
index 0000000..20c9929
--- /dev/null
+++ b/gdb/testsuite/gdb.base/watchpoint-delete.c
@@ -0,0 +1,33 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2010, 2011 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 <http://www.gnu.org/licenses/>. */
+
+void
+func (void)
+{
+ volatile int x = 0;
+
+ x++; /* break-here */
+ x++;
+}
+
+int
+main (void)
+{
+ func ();
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.base/watchpoint-delete.exp b/gdb/testsuite/gdb.base/watchpoint-delete.exp
new file mode 100644
index 0000000..7aadf4e
--- /dev/null
+++ b/gdb/testsuite/gdb.base/watchpoint-delete.exp
@@ -0,0 +1,38 @@
+# Copyright 2010, 2011 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 <http://www.gnu.org/licenses/>.
+
+set testfile "watchpoint-delete"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile}] } {
+ untested ${testfile}.exp
+ return -1
+}
+
+# It is more compatible this way.
+gdb_test_no_output "set can-use-hw-watchpoints 0"
+
+if ![runto_main] {
+ return -1
+}
+
+# Ensure there is a parent frame to create related bp_watchpoint_scope.
+gdb_breakpoint [gdb_get_line_number "break-here"]
+gdb_continue_to_breakpoint "break-here" ".* break-here .*"
+
+gdb_test "watch x" {Watchpoint [0-9]+: x}
+
+gdb_test_no_output {delete $bpnum}
diff --git a/gdb/testsuite/gdb.cp/nextoverthrow.exp b/gdb/testsuite/gdb.cp/nextoverthrow.exp
index 89c02d6..a970bb9 100644
--- a/gdb/testsuite/gdb.cp/nextoverthrow.exp
+++ b/gdb/testsuite/gdb.cp/nextoverthrow.exp
@@ -53,6 +53,17 @@ gdb_test_multiple "print _Unwind_DebugHook" "check for unwinder hook" {
}
}
if {!$ok} {
+ gdb_test_multiple "info probe" "check for stap probe in unwinder" {
+ -re ".*libgcc.*unwind.*\r\n$gdb_prompt $" {
+ pass "check for stap probe in unwinder"
+ set ok 1
+ }
+ -re "\r\n$gdb_prompt $" {
+ }
+ }
+}
+
+if {!$ok} {
unsupported "nextoverthrow.exp could not find _Unwind_DebugHook"
return -1
}
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-bound-loclist.S b/gdb/testsuite/gdb.dwarf2/dw2-bound-loclist.S
new file mode 100644
index 0000000..aac3baa
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-bound-loclist.S
@@ -0,0 +1,246 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2010 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 <http://www.gnu.org/licenses/>. */
+
+/* Debug information */
+
+/* We will `break *main' at the very first instruction. */
+#define main_length 1
+
+ .section .data
+vardata:
+ /* See DW_OP_lit3 + 1 (0-based). */
+ .string "seennotseen"
+
+ .section .debug_info
+.Lcu1_begin:
+ .4byte .Lcu1_end - .Lcu1_start /* Length of Compilation Unit */
+.Lcu1_start:
+ .2byte 2 /* DWARF version number */
+ .4byte .Ldebug_abbrev0 /* Offset Into Abbrev. Section */
+ .byte 4 /* Pointer Size (in bytes) */
+
+ /* CU die */
+ .uleb128 1 /* Abbrev: DW_TAG_compile_unit */
+ .4byte .Lproducer /* DW_AT_producer */
+ /* Use C++ to exploit a bug in parsing DW_AT_name "". */
+ .byte 4 /* DW_AT_language (C++) - */
+ .4byte main /* DW_AT_low_pc */
+ .byte main_length /* DW_AT_high_pc */
+
+.Larray_type:
+ .uleb128 2 /* Abbrev: DW_TAG_array_type */
+ .4byte .Lchar_type-.Lcu1_begin /* DW_AT_type */
+
+ .uleb128 3 /* Abbrev: DW_TAG_subrange_type */
+ .4byte .Luint_type-.Lcu1_begin /* DW_AT_type */
+ .byte 0 /* DW_AT_lower_bound */
+ .4byte .Llen_var-.Lcu1_begin /* DW_AT_upper_bound */
+ .byte 0 /* End of children of die */
+
+ /* DW_AT_upper_bound is referencing an optimized-out variable. */
+.Larrayb_type:
+ .uleb128 2 /* Abbrev: DW_TAG_array_type */
+ .4byte .Lchar_type-.Lcu1_begin /* DW_AT_type */
+
+ .uleb128 3 /* Abbrev: DW_TAG_subrange_type */
+ .4byte .Luint_type-.Lcu1_begin /* DW_AT_type */
+ .byte 0 /* DW_AT_lower_bound */
+ .4byte .Llenb_var-.Lcu1_begin /* DW_AT_upper_bound */
+ .byte 0 /* End of children of die */
+
+ /* DW_AT_upper_bound is referencing register. */
+.Larrayreg_type:
+ .uleb128 2 /* Abbrev: DW_TAG_array_type */
+ .4byte .Lchar_type-.Lcu1_begin /* DW_AT_type */
+
+ .uleb128 8 /* Abbrev: DW_TAG_subrange_type with block */
+ .4byte .Luint_type-.Lcu1_begin /* DW_AT_type */
+ .byte 0 /* DW_AT_lower_bound */
+ .byte 2f - 1f /* DW_AT_upper_bound */
+1: .byte 0x50 /* DW_OP_reg0 */
+2:
+ .byte 0 /* End of children of die */
+
+.Luint_type:
+ .uleb128 4 /* Abbrev: DW_TAG_base_type */
+ .4byte .Luint_str /* DW_AT_name */
+ .byte 4 /* DW_AT_byte_size */
+ .byte 7 /* DW_AT_encoding */
+
+.Lchar_type:
+ .uleb128 4 /* Abbrev: DW_TAG_base_type */
+ .4byte .Lchar_str /* DW_AT_name */
+ .byte 1 /* DW_AT_byte_size */
+ .byte 6 /* DW_AT_encoding */
+
+.Llen_var:
+ .uleb128 5 /* Abbrev: DW_TAG_variable artificial */
+ .byte 1 /* DW_AT_artificial */
+ .4byte .Luint_type-.Lcu1_begin /* DW_AT_type */
+ .4byte .Llen_loclist-.Lloclist /* DW_AT_location */
+
+ /* optimized-out variable for b_string. */
+.Llenb_var:
+ .uleb128 7 /* Abbrev: DW_TAG_variable artificial no DW_AT_location */
+ .byte 1 /* DW_AT_artificial */
+ .4byte .Luint_type-.Lcu1_begin /* DW_AT_type */
+
+ .uleb128 6 /* Abbrev: DW_TAG_variable DW_FORM_string */
+ .string "a_string" /* DW_AT_name */
+ .4byte .Larray_type-.Lcu1_begin /* DW_AT_type */
+ .byte 2f - 1f /* DW_AT_location */
+1: .byte 3 /* DW_OP_addr */
+ .4byte vardata /* <addr> */
+2:
+
+ /* DW_AT_upper_bound is referencing an optimized-out variable. */
+ .uleb128 6 /* Abbrev: DW_TAG_variable DW_FORM_string */
+ .string "b_string" /* DW_AT_name */
+ .4byte .Larrayb_type-.Lcu1_begin /* DW_AT_type */
+ .byte 2f - 1f /* DW_AT_location */
+1: .byte 3 /* DW_OP_addr */
+ .4byte vardata /* <addr> */
+2:
+
+ /* DW_AT_upper_bound is referencing register. */
+ .uleb128 6 /* Abbrev: DW_TAG_variable DW_FORM_string */
+ .string "reg_string" /* DW_AT_name */
+ .4byte .Larrayreg_type-.Lcu1_begin /* DW_AT_type */
+ .byte 2f - 1f /* DW_AT_location */
+1: .byte 3 /* DW_OP_addr */
+ .4byte vardata /* <addr> */
+2:
+
+ .byte 0 /* End of children of CU */
+.Lcu1_end:
+
+ .section .debug_loc
+.Lloclist:
+.Llen_loclist:
+ .4byte 0 # Location list begin address
+ .4byte main_length # Location list end address
+ .value 2f-1f # Location expression size
+1: .byte 0x33 # DW_OP_lit3
+ .byte 0x9f # DW_OP_stack_value
+2:
+ .quad 0x0 # Location list terminator begin (*.LLST2)
+ .quad 0x0 # Location list terminator end (*.LLST2)
+
+ .section .debug_abbrev
+.Ldebug_abbrev0:
+ .uleb128 1 /* Abbrev code */
+ .uleb128 0x11 /* DW_TAG_compile_unit */
+ .byte 0x1 /* has_children */
+ .uleb128 0x25 /* DW_AT_producer */
+ .uleb128 0xe /* DW_FORM_strp */
+ .uleb128 0x13 /* DW_AT_language */
+ .uleb128 0xb /* DW_FORM_data1 */
+ .uleb128 0x11 /* DW_AT_low_pc */
+ .uleb128 0x1 /* DW_FORM_addr */
+ .uleb128 0x12 /* DW_AT_high_pc */
+ .uleb128 0xb /* DW_FORM_data1 */
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
+
+ .uleb128 2 /* Abbrev code */
+ .uleb128 0x1 /* TAG: DW_TAG_array_type */
+ .byte 0x1 /* DW_children_yes */
+ .uleb128 0x49 /* DW_AT_type */
+ .uleb128 0x13 /* DW_FORM_ref4 */
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
+
+ .uleb128 3 /* Abbrev code */
+ .uleb128 0x21 /* DW_TAG_subrange_type */
+ .byte 0x0 /* no children */
+ .uleb128 0x49 /* DW_AT_type */
+ .uleb128 0x13 /* DW_FORM_ref4 */
+ .uleb128 0x22 /* DW_AT_lower_bound */
+ .uleb128 0xb /* DW_FORM_data1 */
+ .uleb128 0x2f /* DW_AT_upper_bound */
+ .uleb128 0x13 /* DW_FORM_ref4 */
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
+
+ .uleb128 4 /* Abbrev code */
+ .uleb128 0x24 /* DW_TAG_base_type */
+ .byte 0x0 /* no_children */
+ .uleb128 0x3 /* DW_AT_name */
+ .uleb128 0xe /* DW_FORM_strp */
+ .uleb128 0xb /* DW_AT_byte_size */
+ .uleb128 0xb /* DW_FORM_data1 */
+ .uleb128 0x3e /* DW_AT_encoding */
+ .uleb128 0xb /* DW_FORM_data1 */
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
+
+ .uleb128 5 /* Abbrev code */
+ .uleb128 0x34 /* DW_TAG_variable */
+ .byte 0x0 /* no_children */
+ .uleb128 0x34 /* DW_AT_artificial */
+ .uleb128 0x0c /* DW_FORM_flag */
+ .uleb128 0x49 /* DW_AT_type */
+ .uleb128 0x13 /* DW_FORM_ref4 */
+ .uleb128 0x02 /* DW_AT_location */
+ .uleb128 0x06 /* DW_FORM_data4 */
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
+
+ .uleb128 6 /* Abbrev code */
+ .uleb128 0x34 /* DW_TAG_variable */
+ .byte 0x0 /* no_children */
+ .uleb128 0x3 /* DW_AT_name */
+ .uleb128 0x8 /* DW_FORM_string */
+ .uleb128 0x49 /* DW_AT_type */
+ .uleb128 0x13 /* DW_FORM_ref4 */
+ .uleb128 0x2 /* DW_AT_location */
+ .uleb128 0xa /* DW_FORM_block1 */
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
+
+ .uleb128 7 /* Abbrev code */
+ .uleb128 0x34 /* DW_TAG_variable */
+ .byte 0x0 /* no_children */
+ .uleb128 0x34 /* DW_AT_artificial */
+ .uleb128 0x0c /* DW_FORM_flag */
+ .uleb128 0x49 /* DW_AT_type */
+ .uleb128 0x13 /* DW_FORM_ref4 */
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
+
+ .uleb128 8 /* Abbrev code */
+ .uleb128 0x21 /* DW_TAG_subrange_type with block */
+ .byte 0x0 /* no children */
+ .uleb128 0x49 /* DW_AT_type */
+ .uleb128 0x13 /* DW_FORM_ref4 */
+ .uleb128 0x22 /* DW_AT_lower_bound */
+ .uleb128 0xb /* DW_FORM_data1 */
+ .uleb128 0x2f /* DW_AT_upper_bound */
+ .uleb128 0xa /* DW_FORM_block1 */
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
+
+ .byte 0x0 /* Terminator */
+
+/* String table */
+ .section .debug_str
+.Lproducer:
+ .string "GNU C 3.3.3"
+.Lchar_str:
+ .string "char"
+.Luint_str:
+ .string "unsigned int"
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-bound-loclist.exp b/gdb/testsuite/gdb.dwarf2/dw2-bound-loclist.exp
new file mode 100644
index 0000000..815ed93
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-bound-loclist.exp
@@ -0,0 +1,54 @@
+# Copyright 2010 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 <http://www.gnu.org/licenses/>.
+
+# Test printing variable with dynamic bounds which reference a different
+# (artificial in the GCC case) variable containing loclist as its location.
+# This testcase uses value (not address) of the referenced variable:
+# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43762
+
+# This test can only be run on targets which support DWARF-2 and use gas.
+# For now pick a sampling of likely targets.
+if {![istarget *-*-linux*]
+ && ![istarget *-*-gnu*]
+ && ![istarget *-*-elf*]
+ && ![istarget *-*-openbsd*]
+ && ![istarget arm-*-eabi*]
+ && ![istarget powerpc-*-eabi*]} {
+ return 0
+}
+
+set testfile dw2-bound-loclist
+if { [prepare_for_testing ${testfile}.exp ${testfile} [list ${testfile}.S main.c] {}] } {
+ return -1
+}
+
+# Verify it behaves at least as an unbound array without inferior.
+
+gdb_test "p a_string" { = 0x[0-9a-f]+ "seennotseen"}
+gdb_test "ptype a_string" {type = char \[\]}
+
+# Not runto_main as dw2-bound-loclist.S handles only the first byte of main.
+if ![runto "*main"] {
+ return -1
+}
+
+gdb_test "p a_string" { = "seen"}
+gdb_test "ptype a_string" {type = char \[4\]}
+
+gdb_test "p b_string" { = (0x[0-9a-f]+ )?"seennotseen"}
+gdb_test "ptype b_string" {type = char \[\]}
+
+# The register contains unpredictable value - the array size.
+gdb_test "ptype reg_string" {type = char \[-?[0-9]+\]}
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-stripped.c b/gdb/testsuite/gdb.dwarf2/dw2-stripped.c
new file mode 100644
index 0000000..1f02d90
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-stripped.c
@@ -0,0 +1,42 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2004 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 2 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ USA. */
+
+
+/* The function `func1' traced into must have debug info on offset > 0;
+ (DW_UNSND (attr)). This is the reason of `func0' existence. */
+
+void
+func0(int a, int b)
+{
+}
+
+/* `func1' being traced into must have some arguments to dump. */
+
+void
+func1(int a, int b)
+{
+ func0 (a,b);
+}
+
+int
+main(void)
+{
+ func1 (1, 2);
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-stripped.exp b/gdb/testsuite/gdb.dwarf2/dw2-stripped.exp
new file mode 100644
index 0000000..1c6e84a
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-stripped.exp
@@ -0,0 +1,79 @@
+# Copyright 2006 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 2 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# Minimal DWARF-2 unit test
+
+# This test can only be run on targets which support DWARF-2.
+# For now pick a sampling of likely targets.
+if {![istarget *-*-linux*]
+ && ![istarget *-*-gnu*]
+ && ![istarget *-*-elf*]
+ && ![istarget *-*-openbsd*]
+ && ![istarget arm-*-eabi*]
+ && ![istarget powerpc-*-eabi*]} {
+ return 0
+}
+
+set testfile "dw2-stripped"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}.x
+
+remote_exec build "rm -f ${binfile}"
+
+# get the value of gcc_compiled
+if [get_compiler_info ${binfile}] {
+ return -1
+}
+
+# This test can only be run on gcc as we use additional_flags=FIXME
+if {$gcc_compiled == 0} {
+ return 0
+}
+
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug additional_flags=-ggdb3}] != "" } {
+ return -1
+}
+
+remote_exec build "objcopy -R .debug_loc ${binfile}"
+set strip_output [remote_exec build "objdump -h ${binfile}"]
+
+set test "stripping test file preservation"
+if [ regexp ".debug_info " $strip_output] {
+ pass "$test (.debug_info preserved)"
+} else {
+ fail "$test (.debug_info got also stripped)"
+}
+
+set test "stripping test file functionality"
+if [ regexp ".debug_loc " $strip_output] {
+ fail "$test (.debug_loc still present)"
+} else {
+ pass "$test (.debug_loc stripped)"
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+# For C programs, "start" should stop in main().
+
+gdb_test "start" \
+ ".*main \\(\\) at .*" \
+ "start"
+gdb_test "step" \
+ "func.* \\(.*\\) at .*" \
+ "step"
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-struct-member-data-location.S b/gdb/testsuite/gdb.dwarf2/dw2-struct-member-data-location.S
new file mode 100644
index 0000000..5fcdd84
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-struct-member-data-location.S
@@ -0,0 +1,83 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2009 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 <http://www.gnu.org/licenses/>. */
+
+/* Debug information */
+
+ .section .debug_info
+.Lcu1_begin:
+ /* CU header */
+ .4byte .Lcu1_end - .Lcu1_start /* Length of Compilation Unit */
+.Lcu1_start:
+ .2byte 2 /* DWARF Version */
+ .4byte .Labbrev1_begin /* Offset into abbrev section */
+ .byte 4 /* Pointer size */
+
+ /* CU die */
+ .uleb128 1 /* Abbrev: DW_TAG_compile_unit */
+ .ascii "dw2-struct-member-data-location.c\0" /* DW_AT_name */
+ .ascii "GNU C 4.3.2\0" /* DW_AT_producer */
+ .byte 1 /* DW_AT_language (C) */
+
+.Ltype_uchar:
+ .uleb128 2 /* Abbrev: DW_TAG_structure_type */
+ .ascii "some_struct\0" /* DW_AT_name */
+
+ .uleb128 3 /* Abbrev: DW_TAG_member */
+ .ascii "field\0" /* DW_AT_name */
+ .byte 0 /* DW_AT_data_member_location */
+
+ .byte 0 /* End of children of some_struct */
+
+ .byte 0 /* End of children of CU */
+
+.Lcu1_end:
+
+/* Abbrev table */
+ .section .debug_abbrev
+.Labbrev1_begin:
+ .uleb128 1 /* Abbrev code */
+ .uleb128 0x11 /* DW_TAG_compile_unit */
+ .byte 1 /* has_children */
+ .uleb128 0x3 /* DW_AT_name */
+ .uleb128 0x8 /* DW_FORM_string */
+ .uleb128 0x25 /* DW_AT_producer */
+ .uleb128 0x8 /* DW_FORM_string */
+ .uleb128 0x13 /* DW_AT_language */
+ .uleb128 0xb /* DW_FORM_data1 */
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
+
+ .uleb128 2 /* Abbrev code */
+ .uleb128 0x13 /* DW_TAG_structure_type */
+ .byte 1 /* has_children */
+ .uleb128 0x3 /* DW_AT_name */
+ .uleb128 0x8 /* DW_FORM_string */
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
+
+ .uleb128 3 /* Abbrev code */
+ .uleb128 0x0d /* DW_TAG_member */
+ .byte 0 /* has_children */
+ .uleb128 0x3 /* DW_AT_name */
+ .uleb128 0x8 /* DW_FORM_string */
+ .uleb128 0x38 /* DW_AT_data_member_location */
+ .uleb128 0x0b /* DW_FORM_data1 */
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
+
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-struct-member-data-location.exp b/gdb/testsuite/gdb.dwarf2/dw2-struct-member-data-location.exp
new file mode 100644
index 0000000..c41151c
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-struct-member-data-location.exp
@@ -0,0 +1,37 @@
+# Copyright 2009 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 <http://www.gnu.org/licenses/>.
+
+# This test can only be run on targets which support DWARF-2 and use gas.
+# For now pick a sampling of likely targets.
+if {![istarget *-*-linux*]
+ && ![istarget *-*-gnu*]
+ && ![istarget *-*-elf*]
+ && ![istarget *-*-openbsd*]
+ && ![istarget arm-*-eabi*]
+ && ![istarget powerpc-*-eabi*]} {
+ return 0
+}
+
+set testfile "dw2-struct-member-data-location"
+set srcfile ${testfile}.S
+set binfile ${testfile}.x
+
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${objdir}/${subdir}/${binfile}" object {nodebug}] != "" } {
+ return -1
+}
+
+clean_restart $binfile
+
+gdb_test "ptype struct some_struct" "type = struct some_struct {\[\r\n \t\]*void field;\[\r\n \t\]*}"
diff --git a/gdb/testsuite/gdb.fortran/dwarf-stride.exp b/gdb/testsuite/gdb.fortran/dwarf-stride.exp
new file mode 100644
index 0000000..cd3486b
--- /dev/null
+++ b/gdb/testsuite/gdb.fortran/dwarf-stride.exp
@@ -0,0 +1,42 @@
+# Copyright 2009 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 2 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# This file was written by Jan Kratochvil <jan.kratochvil@redhat.com>.
+
+# This file is part of the gdb testsuite. Array element stride must not be
+# specified in the number of elements but in a number of bytes instead.
+# Original problem:
+# (gdb) p c40pt(1)
+# $1 = '0-hello', ' ' <repeats 33 times>
+# (gdb) p c40pt(2)
+# warning: Fortran array stride not divisible by the element size
+
+set testfile dwarf-stride
+set srcfile ${testfile}.f90
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} {debug f77}] } {
+ return -1
+}
+
+if ![runto MAIN__] then {
+ perror "couldn't run to breakpoint MAIN__"
+ continue
+}
+
+gdb_breakpoint [gdb_get_line_number "break-here"]
+gdb_continue_to_breakpoint "break-here" ".*break-here.*"
+gdb_test "p c40pt(1)" " = '0-hello.*"
+gdb_test "p c40pt(2)" " = '1-hello.*"
diff --git a/gdb/testsuite/gdb.fortran/dwarf-stride.f90 b/gdb/testsuite/gdb.fortran/dwarf-stride.f90
new file mode 100644
index 0000000..e492b3a
--- /dev/null
+++ b/gdb/testsuite/gdb.fortran/dwarf-stride.f90
@@ -0,0 +1,40 @@
+! Copyright 2009 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 2 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, write to the Free Software
+! Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+!
+! File written by Alan Matsuoka.
+
+program repro
+
+ type small_stride
+ character*40 long_string
+ integer small_pad
+ end type small_stride
+
+ type(small_stride), dimension (20), target :: unpleasant
+ character*40, pointer, dimension(:):: c40pt
+
+ integer i
+
+ do i = 0,19
+ unpleasant(i+1)%small_pad = i+1
+ unpleasant(i+1)%long_string = char (ichar('0') + i) // '-hello'
+ end do
+
+ c40pt => unpleasant%long_string
+
+ print *, c40pt ! break-here
+
+end program repro
diff --git a/gdb/testsuite/gdb.fortran/dynamic-other-frame-stub.f90 b/gdb/testsuite/gdb.fortran/dynamic-other-frame-stub.f90
new file mode 100644
index 0000000..261ce17
--- /dev/null
+++ b/gdb/testsuite/gdb.fortran/dynamic-other-frame-stub.f90
@@ -0,0 +1,24 @@
+! Copyright 2010 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 2 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, write to the Free Software
+! Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+!
+! Ihis file is the Fortran source file for dynamic.exp.
+! Original file written by Jakub Jelinek <jakub@redhat.com>.
+! Modified for the GDB testcase by Jan Kratochvil <jan.kratochvil@redhat.com>.
+
+subroutine bar
+ real :: dummy
+ dummy = 1
+end subroutine bar
diff --git a/gdb/testsuite/gdb.fortran/dynamic-other-frame.exp b/gdb/testsuite/gdb.fortran/dynamic-other-frame.exp
new file mode 100644
index 0000000..4fdd5ee
--- /dev/null
+++ b/gdb/testsuite/gdb.fortran/dynamic-other-frame.exp
@@ -0,0 +1,37 @@
+# Copyright 2010 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 2 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+set testfile "dynamic-other-frame"
+set srcfile1 ${testfile}.f90
+set srcfile2 ${testfile}-stub.f90
+set objfile2 ${objdir}/${subdir}/${testfile}-stub.o
+set executable ${testfile}
+set binfile ${objdir}/${subdir}/${executable}
+
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile2}" "${objfile2}" object {f77}] != ""
+ || [gdb_compile "${srcdir}/${subdir}/${srcfile1} ${objfile2}" "${binfile}" executable {debug f77}] != "" } {
+ untested "Couldn't compile ${srcfile1} or ${srcfile2}"
+ return -1
+}
+
+clean_restart ${executable}
+
+if ![runto bar_] then {
+ perror "couldn't run to bar_"
+ continue
+}
+
+gdb_test "bt" {foo \(string='hello'.*}
diff --git a/gdb/testsuite/gdb.fortran/dynamic-other-frame.f90 b/gdb/testsuite/gdb.fortran/dynamic-other-frame.f90
new file mode 100644
index 0000000..2bc637d
--- /dev/null
+++ b/gdb/testsuite/gdb.fortran/dynamic-other-frame.f90
@@ -0,0 +1,36 @@
+! Copyright 2010 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 2 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, write to the Free Software
+! Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+!
+! Ihis file is the Fortran source file for dynamic.exp.
+! Original file written by Jakub Jelinek <jakub@redhat.com>.
+! Modified for the GDB testcase by Jan Kratochvil <jan.kratochvil@redhat.com>.
+
+subroutine foo (string)
+ interface
+ subroutine bar
+ end subroutine
+ end interface
+ character string*(*)
+ call bar ! stop-here
+end subroutine foo
+program test
+ interface
+ subroutine foo (string)
+ character string*(*)
+ end subroutine
+ end interface
+ call foo ('hello')
+end
diff --git a/gdb/testsuite/gdb.fortran/dynamic.exp b/gdb/testsuite/gdb.fortran/dynamic.exp
new file mode 100644
index 0000000..0ccebe0
--- /dev/null
+++ b/gdb/testsuite/gdb.fortran/dynamic.exp
@@ -0,0 +1,145 @@
+# Copyright 2007 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 2 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# This file was written by Jan Kratochvil <jan.kratochvil@redhat.com>.
+
+# This file is part of the gdb testsuite. It contains tests for dynamically
+# allocated Fortran arrays.
+# It depends on the GCC dynamic Fortran arrays DWARF support:
+# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=22244
+
+set testfile "dynamic"
+set srcfile ${testfile}.f90
+set binfile ${objdir}/${subdir}/${testfile}
+
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug f77 quiet}] != "" } {
+ untested "Couldn't compile ${srcfile}"
+ return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+if ![runto MAIN__] then {
+ perror "couldn't run to breakpoint MAIN__"
+ continue
+}
+
+gdb_breakpoint [gdb_get_line_number "varx-init"]
+gdb_continue_to_breakpoint "varx-init"
+gdb_test "p varx" "\\$\[0-9\]* = <(object|the array) is not allocated>" "p varx unallocated"
+gdb_test "ptype varx" "type = <(object|the array) is not allocated>" "ptype varx unallocated"
+gdb_test "p varx(1,5,17)" "(Cannot access it|Unable to access the object) because the (object|array) is not allocated\\." "p varx(1,5,17) unallocated"
+gdb_test "p varx(1,5,17)=1" "(Cannot access it|Unable to access the object) because the (object|array) is not allocated\\." "p varx(1,5,17)=1 unallocated"
+gdb_test "ptype varx(1,5,17)" "(Cannot access it|Unable to access the object) because the (object|array) is not allocated\\." "ptype varx(1,5,17) unallocated"
+
+gdb_breakpoint [gdb_get_line_number "varx-allocated"]
+gdb_continue_to_breakpoint "varx-allocated"
+# $1 = (( ( 0, 0, 0, 0, 0, 0) ( 0, 0, 0, 0, 0, 0) --- , 0) ) ( ( 0, 0, ...) ...) ...)
+gdb_test "ptype varx" "type = real(\\(kind=4\\)|\\*4) \\(6,5:15,17:28\\)" "ptype varx allocated"
+# Intel Fortran Compiler 10.1.008 uses -1 there, GCC uses 1.
+gdb_test "p l" "\\$\[0-9\]* = (\\.TRUE\\.|4294967295)" "p l if varx allocated"
+
+gdb_breakpoint [gdb_get_line_number "varx-filled"]
+gdb_continue_to_breakpoint "varx-filled"
+gdb_test "p varx(2, 5, 17)" "\\$\[0-9\]* = 6"
+gdb_test "p varx(1, 5, 17)" "\\$\[0-9\]* = 7"
+gdb_test "p varx(2, 6, 18)" "\\$\[0-9\]* = 8"
+gdb_test "p varx(6, 15, 28)" "\\$\[0-9\]* = 9"
+# The latter one is for the Intel Fortran Compiler 10.1.008 pointer type.
+gdb_test "p varv" "\\$\[0-9\]* = (<(object|the array) is not associated>|.*(Cannot access it|Unable to access the object) because the object is not associated.)" "p varv unassociated"
+gdb_test "ptype varv" "type = (<(object|the array) is not associated>|.*(Cannot access it|Unable to access the object) because the object is not associated.)" "ptype varv unassociated"
+
+gdb_breakpoint [gdb_get_line_number "varv-associated"]
+gdb_continue_to_breakpoint "varv-associated"
+gdb_test "p varx(3, 7, 19)" "\\$\[0-9\]* = 6" "p varx(3, 7, 19) with varv associated"
+gdb_test "p varv(3, 7, 19)" "\\$\[0-9\]* = 6" "p varv(3, 7, 19) associated"
+# Intel Fortran Compiler 10.1.008 uses -1 there, GCC uses 1.
+gdb_test "p l" "\\$\[0-9\]* = (\\.TRUE\\.|4294967295)" "p l if varv associated"
+gdb_test "ptype varx" "type = real(\\(kind=4\\)|\\*4) \\(6,5:15,17:28\\)" "ptype varx with varv associated"
+# Intel Fortran Compiler 10.1.008 uses the pointer type.
+gdb_test "ptype varv" "type = (PTR TO -> \\( )?real(\\(kind=4\\)|\\*4) \\(6,5:15,17:28\\)\\)?" "ptype varv associated"
+
+gdb_breakpoint [gdb_get_line_number "varv-filled"]
+gdb_continue_to_breakpoint "varv-filled"
+gdb_test "p varx(3, 7, 19)" "\\$\[0-9\]* = 10" "p varx(3, 7, 19) with varv filled"
+gdb_test "p varv(3, 7, 19)" "\\$\[0-9\]* = 10" "p varv(3, 7, 19) filled"
+
+gdb_breakpoint [gdb_get_line_number "varv-deassociated"]
+gdb_continue_to_breakpoint "varv-deassociated"
+# The latter one is for the Intel Fortran Compiler 10.1.008 pointer type.
+gdb_test "p varv" "\\$\[0-9\]* = (<(object|the array) is not associated>|.*(Cannot access it|Unable to access the object) because the object is not associated.)" "p varv deassociated"
+gdb_test "ptype varv" "type = (<(object|the array) is not associated>|.*(Cannot access it|Unable to access the object) because the object is not associated.)" "ptype varv deassociated"
+gdb_test "p l" "\\$\[0-9\]* = \\.FALSE\\." "p l if varv deassociated"
+gdb_test "p varv(1,5,17)" "(Cannot access it|Unable to access the object) because the (object|array) is not associated\\."
+gdb_test "ptype varv(1,5,17)" "(Cannot access it|Unable to access the object) because the (object|array) is not associated\\."
+
+gdb_breakpoint [gdb_get_line_number "varx-deallocated"]
+gdb_continue_to_breakpoint "varx-deallocated"
+gdb_test "p varx" "\\$\[0-9\]* = <(object|the array) is not allocated>" "p varx deallocated"
+gdb_test "ptype varx" "type = <(object|the array) is not allocated>" "ptype varx deallocated"
+gdb_test "p l" "\\$\[0-9\]* = \\.FALSE\\." "p l if varx deallocated"
+gdb_test "p varx(1,5,17)" "(Cannot access it|Unable to access the object) because the (object|array) is not allocated\\." "p varx(1,5,17) deallocated"
+gdb_test "ptype varx(1,5,17)" "(Cannot access it|Unable to access the object) because the (object|array) is not allocated\\." "ptype varx(1,5,17) deallocated"
+
+gdb_breakpoint [gdb_get_line_number "vary-passed"]
+gdb_continue_to_breakpoint "vary-passed"
+# $1 = (( ( 1, 1, 1, 1, 1, 1) ( 1, 1, 1, 1, 1, 1) --- , 1) ) ( ( 1, 1, ...) ...) ...)
+gdb_test "p vary" "\\$\[0-9\]* = \\(\[()1, .\]*\\)"
+
+gdb_breakpoint [gdb_get_line_number "vary-filled"]
+gdb_continue_to_breakpoint "vary-filled"
+gdb_test "ptype vary" "type = real(\\(kind=4\\)|\\*4) \\(10,10\\)"
+gdb_test "p vary(1, 1)" "\\$\[0-9\]* = 8"
+gdb_test "p vary(2, 2)" "\\$\[0-9\]* = 9"
+gdb_test "p vary(1, 3)" "\\$\[0-9\]* = 10"
+# $1 = (( ( 3, 3, 3, 3, 3, 3) ( 3, 3, 3, 3, 3, 3) --- , 3) ) ( ( 3, 3, ...) ...) ...)
+gdb_test "p varw" "\\$\[0-9\]* = \\(\[()3, .\]*\\)"
+
+gdb_breakpoint [gdb_get_line_number "varw-almostfilled"]
+gdb_continue_to_breakpoint "varw-almostfilled"
+gdb_test "ptype varw" "type = real(\\(kind=4\\)|\\*4) \\(5,4,3\\)"
+gdb_test "p varw(3,1,1)=1" "\\$\[0-9\]* = 1"
+# $1 = (( ( 6, 5, 1, 5, 5, 5) ( 5, 5, 5, 5, 5, 5) --- , 5) ) ( ( 5, 5, ...) ...) ...)
+gdb_test "p varw" "\\$\[0-9\]* = \\( *\\( *\\( *6, *5, *1,\[()5, .\]*\\)" "p varw filled"
+# "up" works with GCC but other Fortran compilers may copy the values into the
+# outer function only on the exit of the inner function.
+# We need both variants as depending on the arch we optionally may still be
+# executing the caller line or not after `finish'.
+gdb_test "finish" ".*(call bar \\(y, x\\)|call foo \\(x, z\\(2:6, 4:7, 6:8\\)\\))"
+gdb_test "p z(2,4,5)" "\\$\[0-9\]* = 3"
+gdb_test "p z(2,4,6)" "\\$\[0-9\]* = 6"
+gdb_test "p z(2,4,7)" "\\$\[0-9\]* = 5"
+gdb_test "p z(4,4,6)" "\\$\[0-9\]* = 1"
+
+gdb_breakpoint [gdb_get_line_number "varz-almostfilled"]
+gdb_continue_to_breakpoint "varz-almostfilled"
+# GCC uses the pointer type here, Intel Fortran Compiler 10.1.008 does not.
+gdb_test "ptype varz" "type = (PTR TO -> \\( )?real(\\(kind=4\\)|\\*4) \\(\\*\\)\\)?"
+# Intel Fortran Compiler 10.1.008 has a bug here - (2:11,7:7)
+# as it produces DW_AT_lower_bound == DW_AT_upper_bound == 7.
+gdb_test "ptype vart" "type = (PTR TO -> \\( )?real(\\(kind=4\\)|\\*4) \\(2:11,7:\\*\\)\\)?"
+gdb_test "p varz" "\\$\[0-9\]* = \\(\\)"
+gdb_test "p vart" "\\$\[0-9\]* = \\(\\)"
+gdb_test "p varz(3)" "\\$\[0-9\]* = 4"
+# maps to foo::vary(1,1)
+gdb_test "p vart(2,7)" "\\$\[0-9\]* = 8"
+# maps to foo::vary(2,2)
+gdb_test "p vart(3,8)" "\\$\[0-9\]* = 9"
+# maps to foo::vary(1,3)
+gdb_test "p vart(2,9)" "\\$\[0-9\]* = 10"
diff --git a/gdb/testsuite/gdb.fortran/dynamic.f90 b/gdb/testsuite/gdb.fortran/dynamic.f90
new file mode 100644
index 0000000..0f43564
--- /dev/null
+++ b/gdb/testsuite/gdb.fortran/dynamic.f90
@@ -0,0 +1,98 @@
+! Copyright 2007 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 2 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, write to the Free Software
+! Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+!
+! Ihis file is the Fortran source file for dynamic.exp.
+! Original file written by Jakub Jelinek <jakub@redhat.com>.
+! Modified for the GDB testcase by Jan Kratochvil <jan.kratochvil@redhat.com>.
+
+subroutine baz
+ real, target, allocatable :: varx (:, :, :)
+ real, pointer :: varv (:, :, :)
+ real, target :: varu (1, 2, 3)
+ logical :: l
+ allocate (varx (1:6, 5:15, 17:28)) ! varx-init
+ l = allocated (varx)
+ varx(:, :, :) = 6 ! varx-allocated
+ varx(1, 5, 17) = 7
+ varx(2, 6, 18) = 8
+ varx(6, 15, 28) = 9
+ varv => varx ! varx-filled
+ l = associated (varv)
+ varv(3, 7, 19) = 10 ! varv-associated
+ varv => null () ! varv-filled
+ l = associated (varv)
+ deallocate (varx) ! varv-deassociated
+ l = allocated (varx)
+ varu(:, :, :) = 10 ! varx-deallocated
+ allocate (varv (1:6, 5:15, 17:28))
+ l = associated (varv)
+ varv(:, :, :) = 6
+ varv(1, 5, 17) = 7
+ varv(2, 6, 18) = 8
+ varv(6, 15, 28) = 9
+ deallocate (varv)
+ l = associated (varv)
+ varv => varu
+ varv(1, 1, 1) = 6
+ varv(1, 2, 3) = 7
+ l = associated (varv)
+end subroutine baz
+subroutine foo (vary, varw)
+ real :: vary (:, :)
+ real :: varw (:, :, :)
+ vary(:, :) = 4 ! vary-passed
+ vary(1, 1) = 8
+ vary(2, 2) = 9
+ vary(1, 3) = 10
+ varw(:, :, :) = 5 ! vary-filled
+ varw(1, 1, 1) = 6
+ varw(2, 2, 2) = 7 ! varw-almostfilled
+end subroutine foo
+subroutine bar (varz, vart)
+ real :: varz (*)
+ real :: vart (2:11, 7:*)
+ varz(1:3) = 4
+ varz(2) = 5 ! varz-almostfilled
+ vart(2,7) = vart(2,7)
+end subroutine bar
+program test
+ interface
+ subroutine foo (vary, varw)
+ real :: vary (:, :)
+ real :: varw (:, :, :)
+ end subroutine
+ end interface
+ interface
+ subroutine bar (varz, vart)
+ real :: varz (*)
+ real :: vart (2:11, 7:*)
+ end subroutine
+ end interface
+ real :: x (10, 10), y (5), z(8, 8, 8)
+ x(:,:) = 1
+ y(:) = 2
+ z(:,:,:) = 3
+ call baz
+ call foo (x, z(2:6, 4:7, 6:8))
+ call bar (y, x)
+ if (x (1, 1) .ne. 8 .or. x (2, 2) .ne. 9 .or. x (1, 2) .ne. 4) call abort
+ if (x (1, 3) .ne. 10) call abort
+ if (z (2, 4, 6) .ne. 6 .or. z (3, 5, 7) .ne. 7 .or. z (2, 4, 7) .ne. 5) call abort
+ if (any (y .ne. (/4, 5, 4, 2, 2/))) call abort
+ call foo (transpose (x), z)
+ if (x (1, 1) .ne. 8 .or. x (2, 2) .ne. 9 .or. x (1, 2) .ne. 4) call abort
+ if (x (3, 1) .ne. 10) call abort
+end
diff --git a/gdb/testsuite/gdb.fortran/string.exp b/gdb/testsuite/gdb.fortran/string.exp
new file mode 100644
index 0000000..b1120c3
--- /dev/null
+++ b/gdb/testsuite/gdb.fortran/string.exp
@@ -0,0 +1,59 @@
+# Copyright 2008 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 2 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# This file was written by Jan Kratochvil <jan.kratochvil@redhat.com>.
+
+# This file is part of the gdb testsuite. It contains tests for Fortran
+# strings with dynamic length.
+
+set testfile "string"
+set srcfile ${testfile}.f90
+set binfile ${objdir}/${subdir}/${testfile}
+
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug f77 quiet}] != "" } {
+ untested "Couldn't compile ${srcfile}"
+ return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+if ![runto MAIN__] then {
+ perror "couldn't run to breakpoint MAIN__"
+ continue
+}
+
+gdb_breakpoint [gdb_get_line_number "var-init"]
+gdb_continue_to_breakpoint "var-init"
+gdb_test "ptype c" "type = character(\\(kind=1\\)|\\*1)"
+gdb_test "ptype d" "type = character(\\(kind=8\\)|\\*8)"
+gdb_test "ptype e" "type = character(\\(kind=4\\)|\\*4)"
+gdb_test "ptype f" "type = character(\\(kind=4\\)|\\*4) \\(7,8:10\\)"
+gdb_test "ptype *e" "Attempt to take contents of a non-pointer value."
+gdb_test "ptype *f" "type = character(\\(kind=4\\)|\\*4) \\(7\\)"
+gdb_test "p c" "\\$\[0-9\]* = 'c'"
+gdb_test "p d" "\\$\[0-9\]* = 'd '"
+gdb_test "p e" "\\$\[0-9\]* = 'g '"
+gdb_test "p f" "\\$\[0-9\]* = \\(\\( 'h ', 'h ', 'h ', 'h ', 'h ', 'h ', 'h '\\) \\( 'h ', 'h ', 'h ', 'h ', 'h ', 'h ', 'h '\\) \\( 'h ', 'h ', 'h ', 'h ', 'h ', 'h ', 'h '\\) \\)"
+gdb_test "p *e" "Attempt to take contents of a non-pointer value."
+gdb_test "p *f" "Attempt to take contents of a non-pointer value."
+
+gdb_breakpoint [gdb_get_line_number "var-finish"]
+gdb_continue_to_breakpoint "var-finish"
+gdb_test "p e" "\\$\[0-9\]* = 'e '" "p e re-set"
+gdb_test "p f" "\\$\[0-9\]* = \\(\\( 'f ', 'f ', 'f ', 'f ', 'f ', 'f ', 'f '\\) \\( 'f2 ', 'f ', 'f ', 'f ', 'f ', 'f ', 'f '\\) \\( 'f ', 'f ', 'f ', 'f ', 'f ', 'f ', 'f '\\) \\)" "p *f re-set"
diff --git a/gdb/testsuite/gdb.fortran/string.f90 b/gdb/testsuite/gdb.fortran/string.f90
new file mode 100644
index 0000000..226dc5d
--- /dev/null
+++ b/gdb/testsuite/gdb.fortran/string.f90
@@ -0,0 +1,37 @@
+! Copyright 2008 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 2 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, write to the Free Software
+! Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+!
+! Ihis file is the Fortran source file for dynamic.exp.
+! Original file written by Jakub Jelinek <jakub@redhat.com>.
+! Modified for the GDB testcase by Jan Kratochvil <jan.kratochvil@redhat.com>.
+
+subroutine foo (e, f)
+ character (len=1) :: c
+ character (len=8) :: d
+ character (len=*) :: e
+ character (len=*) :: f (1:7, 8:10)
+ c = 'c'
+ d = 'd'
+ e = 'e' ! var-init
+ f = 'f'
+ f(1,9) = 'f2'
+ c = 'c' ! var-finish
+end subroutine foo
+ character (len=4) :: g, h (1:7, 8:10)
+ g = 'g'
+ h = 'h'
+ call foo (g, h)
+end
diff --git a/gdb/testsuite/gdb.fortran/subrange.exp b/gdb/testsuite/gdb.fortran/subrange.exp
new file mode 100644
index 0000000..be372c1
--- /dev/null
+++ b/gdb/testsuite/gdb.fortran/subrange.exp
@@ -0,0 +1,60 @@
+# Copyright 2011 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 <http://www.gnu.org/licenses/>.
+
+if { [skip_fortran_tests] } { return -1 }
+
+set testfile "subrange"
+set srcfile ${testfile}.f90
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} {debug f77}] } {
+ return -1
+}
+
+if ![runto MAIN__] {
+ perror "Couldn't run to MAIN__"
+ continue
+}
+
+# Depending on the compiler version being used, the name of the 4-byte integer
+# and real types can be printed differently. For instance, gfortran-4.1 uses
+# "int4" whereas gfortran-4.3 uses "int(kind=4)".
+set int4 "(int4|integer\\(kind=4\\))"
+
+gdb_breakpoint [gdb_get_line_number "break-static"]
+gdb_continue_to_breakpoint "break-static" ".*break-static.*"
+
+foreach var {a alloc ptr} {
+ global pf_prefix
+ set old_prefix $pf_prefix
+ lappend pf_prefix "$var:"
+
+ gdb_test "p $var (2, 2:3)" { = \(22, 32\)}
+ gdb_test "p $var (2:3, 3)" { = \(32, 33\)}
+ gdb_test "p $var (1, 2:)" { = \(21, 31\)}
+ gdb_test "p $var (2, :2)" { = \(12, 22\)}
+ gdb_test "p $var (3, 2:2)" { = \(23\)}
+ gdb_test "ptype $var (3, 2:2)" " = $int4 \\(2:2\\)"
+ gdb_test "p $var (4, :)" { = \(14, 24, 34\)}
+ gdb_test "p $var (:, :)" { = \(\( *11, 12, 13, 14\) \( *21, 22, 23, 24\) \( *31, 32, 33, 34\) *\)}
+ gdb_test "ptype $var (:, :)" " = $int4 \\(4,3\\)"
+ gdb_test "p $var (:)" "Wrong number of subscripts"
+ gdb_test "p $var (:, :, :)" "Wrong number of subscripts"
+
+ set pf_prefix $old_prefix
+}
+
+gdb_test_no_output {set $a=a}
+delete_breakpoints
+gdb_unload
+gdb_test {p $a (3, 2:2)} { = \(23\)}
diff --git a/gdb/testsuite/gdb.fortran/subrange.f90 b/gdb/testsuite/gdb.fortran/subrange.f90
new file mode 100644
index 0000000..4747ea9
--- /dev/null
+++ b/gdb/testsuite/gdb.fortran/subrange.f90
@@ -0,0 +1,28 @@
+! Copyright 2011 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 <http://www.gnu.org/licenses/>.
+
+program test
+ integer, target :: a (4, 3)
+ integer, allocatable :: alloc (:, :)
+ integer, pointer :: ptr (:, :)
+ do 1 i = 1, 4
+ do 1 j = 1, 3
+ a (i, j) = j * 10 + i
+1 continue
+ allocate (alloc (4, 3))
+ alloc = a
+ ptr => a
+ write (*,*) a ! break-static
+end
diff --git a/gdb/testsuite/gdb.gdb/selftest.exp b/gdb/testsuite/gdb.gdb/selftest.exp
index 30a71dd..4bb8e7d 100644
--- a/gdb/testsuite/gdb.gdb/selftest.exp
+++ b/gdb/testsuite/gdb.gdb/selftest.exp
@@ -92,6 +92,10 @@ proc do_steps_and_nexts {} {
set description "step over ttyarg initialization"
set command "step"
}
+ -re ".*python_script = 0.*$gdb_prompt $" {
+ set description "step over python_script initialization"
+ set command "step"
+ }
-re ".*pre_stat_chain = make_command_stats_cleanup.*$gdb_prompt $" {
set description "next over make_command_stats_cleanup and everything it calls"
set command "next"
diff --git a/gdb/testsuite/gdb.mi/mi2-var-stale-type.c b/gdb/testsuite/gdb.mi/mi2-var-stale-type.c
new file mode 100644
index 0000000..ebced3c
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi2-var-stale-type.c
@@ -0,0 +1,26 @@
+/* Copyright 2011 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/>. */
+
+int
+main (int argc, char **argv)
+{
+ char vla[argc];
+
+ vla[0] = 0; /* break-here */
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.mi/mi2-var-stale-type.exp b/gdb/testsuite/gdb.mi/mi2-var-stale-type.exp
new file mode 100644
index 0000000..74a104e
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi2-var-stale-type.exp
@@ -0,0 +1,57 @@
+# Copyright 2011 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 <http://www.gnu.org/licenses/>.
+
+load_lib mi-support.exp
+set MIFLAGS "-i=mi2"
+
+gdb_exit
+if [mi_gdb_start] {
+ continue
+}
+
+set testfile "mi2-var-stale-type"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+if {[build_executable ${testfile}.exp $testfile $srcfile] == -1} {
+ return -1
+}
+
+mi_delete_breakpoints
+mi_gdb_reinitialize_dir $srcdir/$subdir
+mi_gdb_load ${binfile}
+
+mi_gdb_test {-interpreter-exec console "maintenance set internal-error quit yes"} \
+ {\^done} \
+ "maintenance set internal-error quit yes"
+
+mi_gdb_test {-interpreter-exec console "maintenance set internal-error corefile yes"} \
+ {\^done} \
+ "maintenance set internal-error corefile yes"
+
+set line [gdb_get_line_number "break-here"]
+set func "main"
+
+mi_gdb_test "-break-insert -t $srcfile:$line" \
+ "\\^done,bkpt=\{number=\"\[0-9\]+\",type=\"breakpoint\",disp=\"del\",enabled=\"y\",addr=\"$hex\",func=\"$func\(\\\(.*\\\)\)?\",file=\".*\",line=\"$line\",times=\"0\",original-location=\".*\"\}" \
+ "breakpoint at $func"
+
+if { [mi_run_cmd] < 0 } {
+ return -1
+}
+mi_expect_stop "breakpoint-hit" $func ".*" ".*" "\[0-9\]+" { "" "disp=\"del\"" } "stop after initializing vla"
+
+mi_create_varobj "vla" "vla" "create local variable vla"
+
+mi_gdb_test "-var-update *" "\\^done,changelist=.*" "-var-update *"
diff --git a/gdb/testsuite/gdb.multi/watchpoint-multi.c b/gdb/testsuite/gdb.multi/watchpoint-multi.c
new file mode 100644
index 0000000..153c18b
--- /dev/null
+++ b/gdb/testsuite/gdb.multi/watchpoint-multi.c
@@ -0,0 +1,59 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2010 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 <http://www.gnu.org/licenses/>. */
+
+#include <pthread.h>
+#include <assert.h>
+
+static volatile int a, b, c;
+
+static void
+marker_exit1 (void)
+{
+ a = 1;
+}
+
+/* Workaround PR breakpoints/12272 by two different breakpoint locations. */
+static void
+marker_exit2 (void)
+{
+ a = 1;
+}
+
+static void *
+start (void *arg)
+{
+ b = 2;
+ c = 3;
+
+ return NULL;
+}
+
+int
+main (void)
+{
+ pthread_t thread;
+ int i;
+
+ i = pthread_create (&thread, NULL, start, NULL);
+ assert (i == 0);
+ i = pthread_join (thread, NULL);
+ assert (i == 0);
+
+ marker_exit1 ();
+ marker_exit2 ();
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.multi/watchpoint-multi.exp b/gdb/testsuite/gdb.multi/watchpoint-multi.exp
new file mode 100644
index 0000000..97fa6cd
--- /dev/null
+++ b/gdb/testsuite/gdb.multi/watchpoint-multi.exp
@@ -0,0 +1,113 @@
+# Copyright 2010 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 <http://www.gnu.org/licenses/>.
+
+if { [is_remote target] || ![isnative] } then {
+ continue
+}
+
+set testfile "watchpoint-multi"
+
+set executable ${testfile}
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${executable}
+
+if { [gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+ untested ${testfile}.exp
+ return -1
+}
+
+clean_restart $executable
+
+if ![runto_main] {
+ return
+}
+# Never keep/use any non-hw breakpoints to workaround a multi-inferior bug.
+delete_breakpoints
+
+gdb_test "add-inferior" "Added inferior 2"
+gdb_test "inferior 2" "witching to inferior 2 .*"
+gdb_load $binfile
+
+if ![runto_main] {
+ return
+}
+delete_breakpoints
+
+# Simulate non-stop+target-async which also uses breakpoint always-inserted.
+gdb_test_no_output "set breakpoint always-inserted on"
+# displaced-stepping is also needed as other GDB sometimes still removes the
+# breakpoints, even with always-inserted on.
+gdb_test_no_output "set displaced-stepping on"
+
+# Debugging of this testcase:
+#gdb_test_no_output "maintenance set show-debug-regs on"
+#gdb_test_no_output "set debug infrun 1"
+
+# Do not use simple hardware watchpoint ("watch") as its false hit may be
+# unnoticed by GDB if it reads it still has the same value.
+gdb_test "awatch c" "Hardware access \\(read/write\\) watchpoint \[0-9\]+: c"
+# Never keep/use any non-hw breakpoints to workaround a multi-inferior bug.
+# Use `*' to workaround a multi-inferior bug.
+set test "hbreak *marker_exit2"
+gdb_test_multiple $test $test {
+ -re "Hardware assisted breakpoint \[0-9\]+ at .*\r\n$gdb_prompt $" {
+ pass $test
+ }
+ -re "(No hardware breakpoint support in the target\\.|Hardware breakpoints used exceeds limit\\.)\r\n$gdb_prompt $" {
+ pass $test
+ untested ${testfile}.exp
+ return
+ }
+}
+
+gdb_test "inferior 1" "witching to inferior 1 .*"
+
+gdb_test "awatch b" "Hardware access \\(read/write\\) watchpoint \[0-9\]+: b"
+gdb_test "hbreak *marker_exit1" {Hardware assisted breakpoint [0-9]+ at .*}
+
+gdb_test "inferior 2" "witching to inferior 2 .*"
+
+# FAIL would be a hit on watchpoint for `b' - that one is for the other
+# inferior.
+gdb_test "continue" "Hardware access \\(read/write\\) watchpoint \[0-9\]+: c\r\n\r\nOld value = 0\r\nNew value = 3\r\n.*" "catch c"
+
+set test "catch marker_exit2"
+gdb_test_multiple "continue" $test {
+ -re "Breakpoint \[0-9\]+, marker_exit2 .*\r\n$gdb_prompt $" {
+ setup_kfail breakpoints/12312 *-*-*
+ pass $test
+ }
+ -re "Hardware access \\(read/write\\) watchpoint \[0-9\]+: c\r\n\r\nValue = 3\r\n(.* in )?__nptl_death_event .*\r\n$gdb_prompt $" {
+ setup_kfail breakpoints/12312 *-*-*
+ fail $test
+ }
+}
+
+gdb_test "inferior 1" "witching to inferior 1 .*"
+
+gdb_test "continue" "Hardware access \\(read/write\\) watchpoint \[0-9\]+: b\r\n\r\nOld value = 0\r\nNew value = 2\r\n.*" "catch b"
+
+set test "catch marker_exit1"
+gdb_test_multiple "continue" $test {
+ -re "Breakpoint \[0-9\]+, marker_exit1 .*\r\n$gdb_prompt $" {
+ setup_kfail breakpoints/12312 *-*-*
+ pass $test
+ }
+ -re "Hardware access \\(read/write\\) watchpoint \[0-9\]+: b\r\n\r\nValue = 2\r\n(.* in )?__nptl_death_event .*\r\n$gdb_prompt $" {
+ setup_kfail breakpoints/12312 *-*-*
+ fail $test
+ }
+}
+
diff --git a/gdb/testsuite/gdb.opt/array-from-register-func.c b/gdb/testsuite/gdb.opt/array-from-register-func.c
new file mode 100644
index 0000000..729f457
--- /dev/null
+++ b/gdb/testsuite/gdb.opt/array-from-register-func.c
@@ -0,0 +1,22 @@
+/* This file is part of GDB, the GNU debugger.
+
+ Copyright 2009 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 <http://www.gnu.org/licenses/>. */
+
+int
+func (int *arr)
+{
+ return arr[0];
+}
diff --git a/gdb/testsuite/gdb.opt/array-from-register.c b/gdb/testsuite/gdb.opt/array-from-register.c
new file mode 100644
index 0000000..3090e7e
--- /dev/null
+++ b/gdb/testsuite/gdb.opt/array-from-register.c
@@ -0,0 +1,28 @@
+/* This file is part of GDB, the GNU debugger.
+
+ Copyright 2009 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 <http://www.gnu.org/licenses/>. */
+
+extern int func (int *arr);
+
+int
+main (void)
+{
+ int arr[] = { 42 };
+
+ func (arr);
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.opt/array-from-register.exp b/gdb/testsuite/gdb.opt/array-from-register.exp
new file mode 100644
index 0000000..f2de718
--- /dev/null
+++ b/gdb/testsuite/gdb.opt/array-from-register.exp
@@ -0,0 +1,33 @@
+# Copyright 2009 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 2 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# This file is part of the gdb testsuite.
+
+if { [prepare_for_testing array-from-register.exp "array-from-register" \
+ {array-from-register.c array-from-register-func.c} \
+ {debug optimize=-O2}] } {
+ return -1
+}
+
+if ![runto func] then {
+ return -1
+}
+
+gdb_test "p arr" "\\$\[0-9\]+ = \\(int \\*\\) *0x\[0-9a-f\]+"
+
+# Seen regression:
+# Address requested for identifier "arr" which is in register $rdi
+gdb_test "p arr\[0\]" "\\$\[0-9\]+ = 42"
diff --git a/gdb/testsuite/gdb.pascal/arrays.exp b/gdb/testsuite/gdb.pascal/arrays.exp
new file mode 100644
index 0000000..ccc6e1e
--- /dev/null
+++ b/gdb/testsuite/gdb.pascal/arrays.exp
@@ -0,0 +1,104 @@
+# Copyright 2008, 2009 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 <http://www.gnu.org/licenses/>.
+
+if $tracelevel then {
+ strace $tracelevel
+}
+
+load_lib "pascal.exp"
+
+set testfile "arrays"
+set srcfile ${testfile}.pas
+set binfile ${objdir}/${subdir}/${testfile}$EXEEXT
+
+# These tests only work with fpc, using the -gw3 compile-option
+pascal_init
+if { $pascal_compiler_is_fpc != 1 } {
+ return -1
+}
+
+# Detect if the fpc version is below 2.3.0
+set fpc_generates_dwarf_for_dynamic_arrays 1
+if { ($fpcversion_major < 2) || ( ($fpcversion_major == 2) && ($fpcversion_minor < 3))} {
+ set fpc_generates_dwarf_for_dynamic_arrays 0
+}
+
+
+if {[gdb_compile_pascal "-gw3 ${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug ]] != "" } {
+ return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+set bp_location1 [gdb_get_line_number "set breakpoint 1 here"]
+set bp_location2 [gdb_get_line_number "set breakpoint 2 here"]
+
+
+if { [gdb_breakpoint ${srcfile}:${bp_location1}] } {
+ pass "setting breakpoint 1"
+}
+if { [gdb_breakpoint ${srcfile}:${bp_location2}] } {
+ pass "setting breakpoint 2"
+}
+
+# Verify that "start" lands inside the right procedure.
+if { [gdb_start_cmd] < 0 } {
+ untested start
+ return -1
+}
+
+gdb_test "" ".* at .*${srcfile}.*" "start"
+
+gdb_test "cont" "Breakpoint .*:${bp_location1}.*" "Going to first breakpoint"
+
+gdb_test "print StatArrInt" ".* = \\{50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61\\}" "Print static array of integer type"
+gdb_test "print StatArrInt_" ".* = \\{50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61\\}" "Print static array of integer"
+
+gdb_test "cont" "Breakpoint .*:${bp_location2}.*" "Going to second breakpoint"
+
+gdb_test "print StatArrChar" ".* = 'abcdefghijkl'" "Print static array of char"
+gdb_test "print Stat2dArrInt" ".* = \\{\\{0, 1, 2, 3, 4\\}, \\{1, 2, 3, 4, 5\\}, \\{2, 3, 4, 5, 6\\}, \\{3, 4, 5, 6, 7\\}, \\{4, 5, 6, 7, 8\\}, \\{5, 6, 7, 8, 9\\}, \\{6, 7, 8, 9, 10\\}, \\{7, 8, 9, 10, 11\\}, \\{8, 9, 10, 11, 12\\}, \\{9, 10, 11, 12, 13\\}, \\{10, 11, 12, 13, 14\\}, \\{11, 12, 13, 14, 15\\}\\}" "Print static 2-dimensional array of integer"
+
+if { $fpc_generates_dwarf_for_dynamic_arrays == 0} {
+ setup_xfail "*-*-*"
+}
+gdb_test "print DynArrInt" ".* = \\{50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62\\}" "Print dynamic array of integer type"
+if { $fpc_generates_dwarf_for_dynamic_arrays == 0} {
+ setup_xfail "*-*-*"
+}
+gdb_test "print DynArrInt_" ".* = \\{50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62\\}" "Print dynamic array of integer"
+
+if { $fpc_generates_dwarf_for_dynamic_arrays == 0} {
+ setup_xfail "*-*-*"
+}
+gdb_test "print s" ".* = 'test'#0'string'" "Print string containing null-char"
+
+if { $fpc_generates_dwarf_for_dynamic_arrays == 0} {
+ setup_xfail "*-*-*"
+}
+gdb_test "print DynArrStr" ".* = \\{'dstr0', 'dstr1', 'dstr2', 'dstr3', 'dstr4', 'dstr5', 'dstr6', 'dstr7', 'dstr8', 'dstr9', 'dstr10', 'dstr11', 'dstr12'\\}" "Print dynamic array of string"
+
+if { $fpc_generates_dwarf_for_dynamic_arrays == 0} {
+ setup_xfail "*-*-*"
+}
+gdb_test "print StatArrStr" ".* = \\{'str0', 'str1', 'str2', 'str3', 'str4', 'str5', 'str6', 'str7', 'str8', 'str9', 'str10', 'str11', 'str12'\\}" "Print static array of string"
+
+if { $fpc_generates_dwarf_for_dynamic_arrays == 0} {
+ setup_xfail "*-*-*"
+}
+gdb_test "print DynArrChar" ".* = 'abcdefghijklm'" "Print dynamic array of char"
+
diff --git a/gdb/testsuite/gdb.pascal/arrays.pas b/gdb/testsuite/gdb.pascal/arrays.pas
new file mode 100644
index 0000000..295602d
--- /dev/null
+++ b/gdb/testsuite/gdb.pascal/arrays.pas
@@ -0,0 +1,82 @@
+{
+ Copyright 2008, 2009 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 <http://www.gnu.org/licenses/>.
+}
+
+program arrays;
+
+{$mode objfpc}{$h+}
+
+uses sysutils;
+
+type TStatArrInt= array[0..11] of integer;
+ TDynArrInt= array of integer;
+ TStatArrStr= array[0..12] of string;
+ TDynArrStr= array of string;
+ TDynArrChar = array of char;
+ TStatArrChar = array [0..11] of char;
+
+ TStat2dArrInt = array[0..11,0..4] of integer;
+
+var StatArrInt: TStatArrInt;
+ StatArrInt_: Array[0..11] of integer;
+ DynArrInt: TDynArrInt;
+ DynArrInt_: Array of integer;
+ StatArrStr: TStatArrStr;
+ DynArrStr: TDynArrStr;
+ StatArrChar: TStatArrChar;
+ DynArrChar: TDynArrChar;
+
+ Stat2dArrInt: TStat2dArrInt;
+
+ s: string;
+
+ i,j : integer;
+
+begin
+ for i := 0 to 11 do
+ begin
+ StatArrInt[i]:= i+50;
+ StatArrInt_[i]:= i+50;
+ StatArrChar[i]:= chr(ord('a')+i);
+ for j := 0 to 4 do
+ Stat2dArrInt[i,j]:=i+j;
+ end;
+ writeln(StatArrInt_[0]);
+ writeln(StatArrInt[0]); { set breakpoint 1 here }
+ writeln(StatArrChar[0]);
+ writeln(Stat2dArrInt[0,0]);
+
+ setlength(DynArrInt,13);
+ setlength(DynArrInt_,13);
+ setlength(DynArrStr,13);
+ setlength(DynArrChar,13);
+ for i := 0 to 12 do
+ begin
+ DynArrInt[i]:= i+50;
+ DynArrInt_[i]:= i+50;
+ DynArrChar[i]:= chr(ord('a')+i);
+ StatArrStr[i]:='str'+inttostr(i);
+ DynArrStr[i]:='dstr'+inttostr(i);
+ end;
+ writeln(DynArrInt_[1]);
+ writeln(DynArrInt[1]);
+ writeln(DynArrStr[1]);
+ writeln(StatArrStr[1]);
+ writeln(DynArrChar[1]);
+
+ s := 'test'#0'string';
+ writeln(s); { set breakpoint 2 here }
+end.
diff --git a/gdb/testsuite/gdb.python/py-frame.exp b/gdb/testsuite/gdb.python/py-frame.exp
index 1cb573e..3605ee5 100644
--- a/gdb/testsuite/gdb.python/py-frame.exp
+++ b/gdb/testsuite/gdb.python/py-frame.exp
@@ -78,8 +78,6 @@ gdb_test "python print bframe == gdb.newest_frame()" True \
gdb_test "python print 'result =', f0 == f1" " = False" "test equality comparison (false)"
gdb_test "python print 'result =', f0 == f0" " = True" "test equality comparison (true)"
-gdb_test "python print 'result =', f0 != f1" " = True" "test inequality comparison (true)"
-gdb_test "python print 'result =', f0 != f0" " = False" "test inequality comparison (false)"
gdb_test "python print 'result =', f0.is_valid ()" " = True" "test Frame.is_valid"
gdb_test "python print 'result =', f0.name ()" " = f2" "test Frame.name"
gdb_test "python print 'result =', f0.type () == gdb.NORMAL_FRAME" " = True" "test Frame.type"
@@ -94,3 +92,5 @@ gdb_test "python print 'result =', f0.read_var ('variable_which_surely_doesnt_ex
gdb_test "python print 'result =', f0.read_var ('a')" " = 1" "test Frame.read_var - success"
gdb_test "python print 'result =', gdb.selected_frame () == f1" " = True" "test gdb.selected_frame"
+
+gdb_test "python print 'result =', f0.block ()" "<gdb.Block object at 0x\[\[:xdigit:\]\]+>" "test Frame.block"
diff --git a/gdb/testsuite/gdb.python/py-value.exp b/gdb/testsuite/gdb.python/py-value.exp
index e012d53..1bd9e53 100644
--- a/gdb/testsuite/gdb.python/py-value.exp
+++ b/gdb/testsuite/gdb.python/py-value.exp
@@ -318,6 +318,15 @@ proc test_value_after_death {} {
"print value's type"
}
+# Regression test for a cast failure. The bug was that if we cast a
+# value to its own type, gdb could crash. This happened because we
+# could end up double-freeing a struct value.
+proc test_cast_regression {} {
+ gdb_test "python v = gdb.Value(5)" "" "create value for cast test"
+ gdb_test "python v = v.cast(v.type)" "" "cast value for cast test"
+ gdb_test "python print v" "5" "print value for cast test"
+}
+
# Regression test for invalid subscript operations. The bug was that
# the type of the value was not being checked before allowing a
# subscript operation to proceed.
@@ -455,6 +464,7 @@ test_value_in_inferior
test_inferior_function_call
test_lazy_strings
test_value_after_death
+test_cast_regression
# The following test recompiles the binary to test either C or C++
# values.
diff --git a/gdb/testsuite/gdb.threads/watchpoint-fork-child.c b/gdb/testsuite/gdb.threads/watchpoint-fork-child.c
new file mode 100644
index 0000000..a2ad29a
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/watchpoint-fork-child.c
@@ -0,0 +1,127 @@
+/* Test case for forgotten hw-watchpoints after fork()-off of a process.
+
+ Copyright 2008, 2009, 2010 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 2 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <assert.h>
+#include <signal.h>
+#include <stdio.h>
+
+#include "watchpoint-fork.h"
+
+static volatile int usr1_got;
+
+static void
+handler_usr1 (int signo)
+{
+ usr1_got++;
+}
+
+void
+forkoff (int nr)
+{
+ pid_t child, save_parent = getpid ();
+ int i;
+ struct sigaction act, oldact;
+#ifdef THREAD
+ void *thread_result;
+#endif
+
+ memset (&act, 0, sizeof act);
+ act.sa_flags = SA_RESTART;
+ act.sa_handler = handler_usr1;
+ sigemptyset (&act.sa_mask);
+ i = sigaction (SIGUSR1, &act, &oldact);
+ assert (i == 0);
+
+ child = fork ();
+ switch (child)
+ {
+ case -1:
+ assert (0);
+ default:
+ printf ("parent%d: %d\n", nr, (int) child);
+
+ /* Sleep for a while to possibly get incorrectly ATTACH_THREADed by GDB
+ tracing the child fork with no longer valid thread/lwp entries of the
+ parent. */
+
+ i = sleep (2);
+ assert (i == 0);
+
+ /* We must not get caught here (against a forgotten breakpoint). */
+
+ var++;
+ marker ();
+
+#ifdef THREAD
+ /* And neither got caught our thread. */
+
+ step = 99;
+ i = pthread_join (thread, &thread_result);
+ assert (i == 0);
+ assert (thread_result == (void *) 99UL);
+#endif
+
+ /* Be sure our child knows we did not get caught above. */
+
+ i = kill (child, SIGUSR1);
+ assert (i == 0);
+
+ /* Sleep for a while to check GDB's `info threads' no longer tracks us in
+ the child fork. */
+
+ i = sleep (2);
+ assert (i == 0);
+
+ _exit (0);
+ case 0:
+ printf ("child%d: %d\n", nr, (int) getpid ());
+
+ /* Let the parent signal us about its success. Be careful of races. */
+
+ for (;;)
+ {
+ /* Parent either died (and USR1_GOT is zero) or it succeeded. */
+ if (getppid () != save_parent)
+ break;
+ if (kill (getppid (), 0) != 0)
+ break;
+ /* Parent succeeded? */
+ if (usr1_got)
+ break;
+
+#ifdef THREAD
+ i = pthread_yield ();
+ assert (i == 0);
+#endif
+ }
+ assert (usr1_got);
+
+ /* We must get caught here (against a false watchpoint removal). */
+
+ marker ();
+ }
+
+ i = sigaction (SIGUSR1, &oldact, NULL);
+ assert (i == 0);
+}
diff --git a/gdb/testsuite/gdb.threads/watchpoint-fork-mt.c b/gdb/testsuite/gdb.threads/watchpoint-fork-mt.c
new file mode 100644
index 0000000..08a5aff
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/watchpoint-fork-mt.c
@@ -0,0 +1,174 @@
+/* Test case for forgotten hw-watchpoints after fork()-off of a process.
+
+ Copyright 2008, 2009, 2010 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 2 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+#include <asm/unistd.h>
+#include <unistd.h>
+#define gettid() syscall (__NR_gettid)
+
+#include "watchpoint-fork.h"
+
+/* Non-atomic `var++' should not hurt as we synchronize the threads by the STEP
+ variable. Hit-comments need to be duplicite there to catch both at-stops
+ and behind-stops, depending on the target. */
+
+volatile int var;
+
+void
+marker (void)
+{
+}
+
+static void
+empty (void)
+{
+}
+
+static void
+mark_exit (void)
+{
+}
+
+pthread_t thread;
+volatile int step;
+
+static void *
+start (void *arg)
+{
+ int i;
+
+ if (step >= 3)
+ goto step_3;
+
+ while (step != 1)
+ {
+ i = pthread_yield ();
+ assert (i == 0);
+ }
+
+ var++; /* validity-thread-B */
+ empty (); /* validity-thread-B */
+ step = 2;
+ while (step != 3)
+ {
+ if (step == 99)
+ goto step_99;
+
+ i = pthread_yield ();
+ assert (i == 0);
+ }
+
+step_3:
+ if (step >= 5)
+ goto step_5;
+
+ var++; /* after-fork1-B */
+ empty (); /* after-fork1-B */
+ step = 4;
+ while (step != 5)
+ {
+ if (step == 99)
+ goto step_99;
+
+ i = pthread_yield ();
+ assert (i == 0);
+ }
+
+step_5:
+ var++; /* after-fork2-B */
+ empty (); /* after-fork2-B */
+ return (void *) 5UL;
+
+step_99:
+ /* We must not get caught here (against a forgotten breakpoint). */
+ var++;
+ marker ();
+ return (void *) 99UL;
+}
+
+int
+main (void)
+{
+ int i;
+ void *thread_result;
+
+ setbuf (stdout, NULL);
+ printf ("main: %d\n", (int) gettid ());
+
+ /* General hardware breakpoints and watchpoints validity. */
+ marker ();
+ var++; /* validity-first */
+ empty (); /* validity-first */
+
+ i = pthread_create (&thread, NULL, start, NULL);
+ assert (i == 0);
+
+ var++; /* validity-thread-A */
+ empty (); /* validity-thread-A */
+ step = 1;
+ while (step != 2)
+ {
+ i = pthread_yield ();
+ assert (i == 0);
+ }
+
+ /* Hardware watchpoints got disarmed here. */
+ forkoff (1);
+
+ var++; /* after-fork1-A */
+ empty (); /* after-fork1-A */
+ step = 3;
+#ifdef FOLLOW_CHILD
+ /* Spawn new thread as it was deleted in the child of FORK. */
+ i = pthread_create (&thread, NULL, start, NULL);
+ assert (i == 0);
+#endif
+ while (step != 4)
+ {
+ i = pthread_yield ();
+ assert (i == 0);
+ }
+
+ /* A sanity check for double hardware watchpoints removal. */
+ forkoff (2);
+
+ var++; /* after-fork2-A */
+ empty (); /* after-fork2-A */
+ step = 5;
+#ifdef FOLLOW_CHILD
+ /* Spawn new thread as it was deleted in the child of FORK. */
+ i = pthread_create (&thread, NULL, start, NULL);
+ assert (i == 0);
+#endif
+
+ i = pthread_join (thread, &thread_result);
+ assert (i == 0);
+ assert (thread_result == (void *) 5UL);
+
+ mark_exit ();
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.threads/watchpoint-fork-parent.c b/gdb/testsuite/gdb.threads/watchpoint-fork-parent.c
new file mode 100644
index 0000000..82d1182
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/watchpoint-fork-parent.c
@@ -0,0 +1,74 @@
+/* Test case for forgotten hw-watchpoints after fork()-off of a process.
+
+ Copyright 2008, 2009, 2010 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 2 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <assert.h>
+#include <stdio.h>
+#include <sys/wait.h>
+
+#include "watchpoint-fork.h"
+
+void
+forkoff (int nr)
+{
+ pid_t child, pid_got;
+ int exit_code = 42 + nr;
+ int status, i;
+
+ child = fork ();
+ switch (child)
+ {
+ case -1:
+ assert (0);
+ case 0:
+ printf ("child%d: %d\n", nr, (int) getpid ());
+ /* Delay to get both the "child%d" and "parent%d" message printed without
+ a race breaking expect by its endless wait on `$gdb_prompt$':
+ Breakpoint 3, marker () at ../../../gdb/testsuite/gdb.threads/watchpoint-fork.c:33
+ 33 }
+ (gdb) parent2: 14223 */
+ i = sleep (1);
+ assert (i == 0);
+
+ /* We must not get caught here (against a forgotten breakpoint). */
+ var++;
+ marker ();
+
+ _exit (exit_code);
+ default:
+ printf ("parent%d: %d\n", nr, (int) child);
+ /* Delay to get both the "child%d" and "parent%d" message printed, see
+ above. */
+ i = sleep (1);
+ assert (i == 0);
+
+ pid_got = wait (&status);
+ assert (pid_got == child);
+ assert (WIFEXITED (status));
+ assert (WEXITSTATUS (status) == exit_code);
+
+ /* We must get caught here (against a false watchpoint removal). */
+ marker ();
+ }
+}
diff --git a/gdb/testsuite/gdb.threads/watchpoint-fork-st.c b/gdb/testsuite/gdb.threads/watchpoint-fork-st.c
new file mode 100644
index 0000000..a7eeedd
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/watchpoint-fork-st.c
@@ -0,0 +1,61 @@
+/* Test case for forgotten hw-watchpoints after fork()-off of a process.
+
+ Copyright 2008, 2009, 2010 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 2 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "watchpoint-fork.h"
+
+volatile int var;
+
+void
+marker (void)
+{
+}
+
+static void
+mark_exit (void)
+{
+}
+
+int
+main (void)
+{
+ setbuf (stdout, NULL);
+ printf ("main: %d\n", (int) getpid ());
+
+ /* General hardware breakpoints and watchpoints validity. */
+ marker ();
+ var++;
+ /* Hardware watchpoints got disarmed here. */
+ forkoff (1);
+ /* This watchpoint got lost before. */
+ var++;
+ /* A sanity check for double hardware watchpoints removal. */
+ forkoff (2);
+ var++;
+
+ mark_exit ();
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.threads/watchpoint-fork.exp b/gdb/testsuite/gdb.threads/watchpoint-fork.exp
new file mode 100644
index 0000000..117700b
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/watchpoint-fork.exp
@@ -0,0 +1,149 @@
+# Copyright 2008, 2009, 2010 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 <http://www.gnu.org/licenses/>.
+
+# Test case for forgotten hw-watchpoints after fork()-off of a process.
+
+proc test {type symbol} {
+ global objdir subdir srcdir gdb_prompt
+
+ set testfile watchpoint-fork
+
+ global pf_prefix
+ set prefix_test $pf_prefix
+ lappend pf_prefix "$type:"
+ set prefix_mt $pf_prefix
+
+ set srcfile_type ${srcdir}/${subdir}/${testfile}-${type}.c
+
+
+ # no threads
+
+ set pf_prefix $prefix_mt
+ lappend pf_prefix "singlethreaded:"
+
+ set executable ${testfile}-${type}-st
+ set srcfile_main ${srcdir}/${subdir}/${testfile}-st.c
+ if { [gdb_compile "${srcfile_main} ${srcfile_type}" ${objdir}/${subdir}/${executable} executable [list debug additional_flags=-D$symbol]] != "" } {
+ untested ${testfile}.exp
+ return
+ }
+ clean_restart $executable
+
+ gdb_test "show detach-on-fork" "Whether gdb will detach the child of a fork is on\\."
+ gdb_test_no_output "set follow-fork-mode $type"
+ gdb_test "show follow-fork-mode" "Debugger response to a program call of fork or vfork is \"$type\"\\."
+ # Testcase uses it for the `follow-fork-mode child' type.
+ gdb_test "handle SIGUSR1 nostop noprint pass" "No\[ \t\]+No\[ \t\]+Yes.*"
+
+ if ![runto_main] {
+ return
+ }
+
+ gdb_test "watch var" "atchpoint \[0-9\]+: var" "Set the watchpoint"
+
+ # It is never hit but it should not be left over in the fork()ed-off child.
+ set hbreak "hbreak"
+ set test "hbreak marker"
+ gdb_test_multiple $test $test {
+ -re "Hardware assisted breakpoint \[0-9\]+ at .*\r\n$gdb_prompt $" {
+ pass $test
+ }
+ -re "(No hardware breakpoint support in the target\\.|Hardware breakpoints used exceeds limit\\.)\r\n$gdb_prompt $" {
+ pass $test
+ set hbreak "break"
+ gdb_test "break marker"
+ }
+ }
+
+ gdb_breakpoint "mark_exit"
+
+ gdb_test "continue" \
+ "reakpoint \[0-9\]+, marker.*" "hardware breakpoints work"
+ gdb_test "continue" \
+ "atchpoint \[0-9\]+: var.*Old value = 0.*New value = 1.*forkoff *\\(1\\).*" "watchpoints work"
+ gdb_test "continue" \
+ "reakpoint \[0-9\]+, marker.*" "breakpoint after the first fork"
+ gdb_test "continue" \
+ "atchpoint \[0-9\]+: var.*Old value = 1.*New value = 2.*forkoff *\\(2\\).*" "watchpoint after the first fork"
+ gdb_test "continue" \
+ "reakpoint \[0-9\]+, marker.*" "breakpoint after the second fork"
+ gdb_test "continue" \
+ "atchpoint \[0-9\]+: var.*Old value = 2.*New value = 3.*mark_exit \\(\\);" "watchpoint after the second fork"
+ gdb_test "continue" "Continuing\\..*\r\nBreakpoint \[0-9\]+, mark_exit .*" "finish"
+
+
+ # threads
+
+ set pf_prefix $prefix_mt
+ lappend pf_prefix "multithreaded:"
+
+ set executable ${testfile}-${type}-mt
+ set srcfile_main ${srcdir}/${subdir}/${testfile}-mt.c
+ if { [gdb_compile_pthreads "${srcfile_main} ${srcfile_type}" ${objdir}/${subdir}/${executable} executable [list debug "additional_flags=-D$symbol -DTHREAD"]] != "" } {
+ untested ${testfile}.exp
+ return
+ }
+ clean_restart $executable
+
+ gdb_test_no_output "set follow-fork-mode $type"
+ # Testcase uses it for the `follow-fork-mode child' type.
+ gdb_test "handle SIGUSR1 nostop noprint pass" "No\[ \t\]+No\[ \t\]+Yes.*"
+
+ if ![runto_main] {
+ return
+ }
+
+ gdb_test "watch var" "atchpoint \[0-9\]+: var" "Set the watchpoint"
+
+ # It should not be left over in the fork()ed-off child.
+ gdb_test "$hbreak marker" {reakpoint [0-9]+.*}
+
+ gdb_breakpoint "mark_exit"
+
+ gdb_test "continue" \
+ "reakpoint \[0-9\]+, marker.*" "hardware breakpoints work"
+ gdb_test "continue" \
+ "atchpoint \[0-9\]+: var.*Old value = 0.*New value = 1.*validity-first.*" "singlethread watchpoints work"
+ gdb_test "continue" \
+ "atchpoint \[0-9\]+: var.*Old value = 1.*New value = 2.*validity-thread-A.*" "multithreaded watchpoints work at A"
+ gdb_test "continue" \
+ "atchpoint \[0-9\]+: var.*Old value = 2.*New value = 3.*validity-thread-B.*" "multithreaded watchpoints work at B"
+ gdb_test "continue" \
+ "reakpoint \[0-9\]+, marker.*" "breakpoint (A) after the first fork"
+ gdb_test "continue" \
+ "atchpoint \[0-9\]+: var.*Old value = 3.*New value = 4.*after-fork1-A.*" "watchpoint A after the first fork"
+ gdb_test "continue" \
+ "atchpoint \[0-9\]+: var.*Old value = 4.*New value = 5.*after-fork1-B.*" "watchpoint B after the first fork"
+ gdb_test "continue" \
+ "reakpoint \[0-9\]+, marker.*" "breakpoint (A) after the second fork"
+ gdb_test "continue" \
+ "atchpoint \[0-9\]+: var.*Old value = 5.*New value = 6.*after-fork2-A.*" "watchpoint A after the second fork"
+ gdb_test "continue" \
+ "atchpoint \[0-9\]+: var.*Old value = 6.*New value = 7.*after-fork2-B.*" "watchpoint B after the second fork"
+ gdb_test "continue" "Continuing\\..*\r\nBreakpoint \[0-9\]+, mark_exit .*" "finish"
+
+
+ # cleanup
+ set pf_prefix $prefix_test
+}
+
+test parent FOLLOW_PARENT
+
+# Only GNU/Linux is known to support `set follow-fork-mode child'.
+if {[istarget "*-*-linux*"] && ![is_remote target]} {
+ test child FOLLOW_CHILD
+} else {
+ untested "child"
+}
diff --git a/gdb/testsuite/gdb.threads/watchpoint-fork.h b/gdb/testsuite/gdb.threads/watchpoint-fork.h
new file mode 100644
index 0000000..31f7656
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/watchpoint-fork.h
@@ -0,0 +1,32 @@
+/* Test case for forgotten hw-watchpoints after fork()-off of a process.
+
+ Copyright 2008, 2009, 2010 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 2 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifdef THREAD
+#include <pthread.h>
+
+extern volatile int step;
+extern pthread_t thread;
+#endif /* THREAD */
+
+extern volatile int var;
+
+extern void marker (void);
+extern void forkoff (int nr);
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 6a2f1a2..c75a7f0 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -141,6 +141,11 @@ proc gdb_unload {} {
send_gdb "y\n"
exp_continue
}
+ -re "A program is being debugged already..*Are you sure you want to change the file.*y or n. $"\
+ { send_gdb "y\n"
+ verbose "\t\tUnloading symbols for program being debugged"
+ exp_continue
+ }
-re "Discard symbol table from .*y or n.*$" {
send_gdb "y\n"
exp_continue
diff --git a/gdb/testsuite/lib/pascal.exp b/gdb/testsuite/lib/pascal.exp
index 891da37..236c5ca 100644
--- a/gdb/testsuite/lib/pascal.exp
+++ b/gdb/testsuite/lib/pascal.exp
@@ -37,6 +37,9 @@ proc pascal_init {} {
global pascal_compiler_is_fpc
global gpc_compiler
global fpc_compiler
+ global fpcversion_major
+ global fpcversion_minor
+ global fpcversion_release
global env
if { $pascal_init_done == 1 } {
@@ -64,6 +67,20 @@ proc pascal_init {} {
set pascal_compiler_is_fpc 1
verbose -log "Free Pascal compiler found"
}
+
+ # Detect the fpc-version
+ if { $pascal_compiler_is_fpc == 1 } {
+ set fpcversion_major 1
+ set fpcversion_minor 0
+ set fpcversion_release 0
+ set fpcversion [ remote_exec host $fpc_compiler "-iV" ]
+ if [regexp {.*([0-9]+)\.([0-9]+)\.([0-9]+).?} $fpcversion] {
+ regsub {.*([0-9]+)\.([0-9]+)\.([0-9]+).?\n?.?} $fpcversion {\1} fpcversion_major
+ regsub {.*([0-9]+)\.([0-9]+)\.([0-9]+).?\n?.?} $fpcversion {\2} fpcversion_minor
+ regsub {.*([0-9]+)\.([0-9]+)\.([0-9]+).?\n?.?} $fpcversion {\3} fpcversion_release
+ }
+ verbose -log "Freepascal version: $fpcversion_major.$fpcversion_minor.$fpcversion_release"
+ }
}
set pascal_init_done 1
}
diff --git a/gdb/thread.c b/gdb/thread.c
index 6ad1807..91fe056 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -1438,7 +1438,8 @@ update_thread_list (void)
no thread is selected, or no threads exist. */
static struct value *
-thread_id_make_value (struct gdbarch *gdbarch, struct internalvar *var)
+thread_id_make_value (struct gdbarch *gdbarch, struct internalvar *var,
+ void *ignore)
{
struct thread_info *tp = find_thread_ptid (inferior_ptid);
@@ -1449,6 +1450,13 @@ thread_id_make_value (struct gdbarch *gdbarch, struct internalvar *var)
/* Commands with a prefix of `thread'. */
struct cmd_list_element *thread_cmd_list = NULL;
+static struct internalvar_funcs thread_funcs =
+{
+ thread_id_make_value,
+ NULL,
+ NULL
+};
+
void
_initialize_thread (void)
{
@@ -1494,5 +1502,5 @@ Show printing of thread events (such as thread start and exit)."), NULL,
show_print_thread_events,
&setprintlist, &showprintlist);
- create_internalvar_type_lazy ("_thread", thread_id_make_value);
+ create_internalvar_type_lazy ("_thread", &thread_funcs, NULL);
}
diff --git a/gdb/top.c b/gdb/top.c
index a25550f..87f0b41 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -343,6 +343,9 @@ void
prepare_execute_command (void)
{
free_all_values ();
+#if 0
+ free_all_types ();
+#endif
/* With multiple threads running while the one we're examining is
stopped, the dcache can get stale without us being able to detect
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index 3ae35d0..e1d2e82 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -4497,7 +4497,8 @@ info_static_tracepoint_markers_command (char *arg, int from_tty)
available. */
static struct value *
-sdata_make_value (struct gdbarch *gdbarch, struct internalvar *var)
+sdata_make_value (struct gdbarch *gdbarch, struct internalvar *var,
+ void *ignore)
{
LONGEST size;
gdb_byte *buf;
@@ -4676,6 +4677,13 @@ traceframe_available_memory (VEC(mem_range_s) **result,
return 0;
}
+static const struct internalvar_funcs sdata_funcs =
+{
+ sdata_make_value,
+ NULL,
+ NULL
+};
+
/* module initialization */
void
_initialize_tracepoint (void)
@@ -4686,7 +4694,7 @@ _initialize_tracepoint (void)
value with a void typed value, and when we get here, gdbarch
isn't initialized yet. At this point, we're quite sure there
isn't another convenience variable of the same name. */
- create_internalvar_type_lazy ("_sdata", sdata_make_value);
+ create_internalvar_type_lazy ("_sdata", &sdata_funcs, NULL);
traceframe_number = -1;
tracepoint_number = -1;
diff --git a/gdb/typeprint.c b/gdb/typeprint.c
index 03e6332..ce6d1e0 100644
--- a/gdb/typeprint.c
+++ b/gdb/typeprint.c
@@ -36,6 +36,7 @@
#include "gdb_string.h"
#include "exceptions.h"
#include "valprint.h"
+#include "dwarf2loc.h"
#include <errno.h>
extern void _initialize_typeprint (void);
@@ -77,6 +78,9 @@ void
type_print (struct type *type, char *varstring, struct ui_file *stream,
int show)
{
+ if (show >= 0)
+ type = check_typedef (type);
+
LA_PRINT_TYPE (type, varstring, stream, show, 0);
}
@@ -115,7 +119,8 @@ whatis_exp (char *exp, int show)
{
struct expression *expr;
struct value *val;
- struct cleanup *old_chain = NULL;
+ /* Required at least for the object_address_set call. */
+ struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
struct type *real_type = NULL;
struct type *type;
int full = 0;
@@ -126,12 +131,13 @@ whatis_exp (char *exp, int show)
if (exp)
{
expr = parse_expression (exp);
- old_chain = make_cleanup (free_current_contents, &expr);
+ make_cleanup (free_current_contents, &expr);
val = evaluate_type (expr);
}
else
val = access_value_history (0);
+ object_address_set (value_raw_address (val));
type = value_type (val);
get_user_print_options (&opts);
@@ -168,8 +174,7 @@ whatis_exp (char *exp, int show)
type_print (type, "", gdb_stdout, show);
printf_filtered ("\n");
- if (exp)
- do_cleanups (old_chain);
+ do_cleanups (old_chain);
}
static void
diff --git a/gdb/utils.c b/gdb/utils.c
index e688d19..f1fc507 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -2243,6 +2243,36 @@ set_batch_flag_and_make_cleanup_restore_page_info (void)
return back_to;
}
+/* Helper for make_cleanup_restore_page_info. */
+
+static void
+do_restore_selected_frame_cleanup (void *arg)
+{
+ struct frame_id *frame_idp = arg;
+
+ select_frame (frame_find_by_id (*frame_idp));
+
+ xfree (frame_idp);
+}
+
+/* Provide cleanup for restoring currently selected frame. Use frame_id for
+ the case the current frame becomes stale in the meantime. */
+
+struct cleanup *
+make_cleanup_restore_selected_frame (void)
+{
+ struct frame_id *frame_idp;
+
+ /* get_selected_frame->get_current_frame would error otherwise. */
+ if (!has_stack_frames ())
+ return make_cleanup (null_cleanup, NULL);
+
+ frame_idp = xmalloc (sizeof (*frame_idp));
+ *frame_idp = get_frame_id (get_selected_frame (NULL));
+
+ return make_cleanup (do_restore_selected_frame_cleanup, frame_idp);
+}
+
/* Set the screen size based on LINES_PER_PAGE and CHARS_PER_LINE. */
static void
diff --git a/gdb/valarith.c b/gdb/valarith.c
index 68f649f..aaa4487 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -198,7 +198,10 @@ value_subscripted_rvalue (struct value *array, LONGEST index, int lowerbound)
struct type *array_type = check_typedef (value_type (array));
struct type *elt_type = check_typedef (TYPE_TARGET_TYPE (array_type));
unsigned int elt_size = TYPE_LENGTH (elt_type);
- unsigned int elt_offs = elt_size * longest_to_int (index - lowerbound);
+ unsigned int elt_stride
+ = (TYPE_BYTE_STRIDE (TYPE_INDEX_TYPE (array_type)) == 0
+ ? elt_size : TYPE_BYTE_STRIDE (TYPE_INDEX_TYPE (array_type)));
+ unsigned int elt_offs = elt_stride * longest_to_int (index - lowerbound);
struct value *v;
if (index < lowerbound || (!TYPE_ARRAY_UPPER_BOUND_IS_UNDEFINED (array_type)
@@ -298,6 +301,10 @@ int
binop_user_defined_p (enum exp_opcode op,
struct value *arg1, struct value *arg2)
{
+ /* FIXME: We should support user defined ops for dynamic types. */
+ if (TYPE_DYNAMIC (value_type (arg1)) || TYPE_DYNAMIC (value_type (arg2)))
+ return 0;
+
return binop_types_user_defined_p (op, value_type (arg1), value_type (arg2));
}
diff --git a/gdb/valops.c b/gdb/valops.c
index b9f5508..1b7ed76 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -47,6 +47,7 @@
#include "objfiles.h"
#include "symtab.h"
#include "exceptions.h"
+#include "dwarf2loc.h"
extern int overload_debug;
/* Local functions. */
@@ -915,6 +916,65 @@ value_one (struct type *type, enum lval_type lv)
return val;
}
+/* object_address_set must be already called before this function. */
+
+const char *
+object_address_data_not_valid (struct type *type)
+{
+ /* Attributes are present only at the target type of a typedef. Make the
+ call conditional as it would otherwise loop through type_length_get. */
+ if (TYPE_CODE (type) == TYPE_CODE_TYPEDEF)
+ CHECK_TYPEDEF (type);
+
+ /* DW_AT_associated has a preference over DW_AT_allocated. */
+ if (TYPE_NOT_ASSOCIATED (type)
+ || (TYPE_ASSOCIATED (type) != NULL
+ && 0 == dwarf_locexpr_baton_eval (TYPE_ASSOCIATED (type))))
+ return N_("object is not associated");
+
+ if (TYPE_NOT_ALLOCATED (type)
+ || (TYPE_ALLOCATED (type) != NULL
+ && 0 == dwarf_locexpr_baton_eval (TYPE_ALLOCATED (type))))
+ return N_("object is not allocated");
+
+ return NULL;
+}
+
+/* Return non-NULL check_typedef result on TYPE if the variable is valid. If
+ it is valid the function may store the data address (DW_AT_DATA_LOCATION) of
+ TYPE at *ADDRESS_RETURN. You must set *ADDRESS_RETURN from
+ value_raw_address (VAL) before calling this function. If no
+ DW_AT_DATA_LOCATION is present for TYPE the address at *ADDRESS_RETURN is
+ left unchanged. ADDRESS_RETURN must not be NULL, use
+ object_address_data_not_valid () for just the data validity check. */
+
+struct type *
+object_address_get_data (struct type *type, CORE_ADDR *address_return)
+{
+ gdb_assert (address_return != NULL);
+
+ object_address_set (*address_return);
+
+ /* TYPE_DATA_LOCATION_DWARF_BLOCK / TYPE_DATA_LOCATION_ADDR are present only
+ at the target type of a typedef. */
+ CHECK_TYPEDEF (type);
+
+ if (object_address_data_not_valid (type) != NULL)
+ {
+ /* Do not try to evaluate DW_AT_data_location as it may even crash
+ (it would just return the value zero in the gfortran case). */
+ return NULL;
+ }
+
+ if (TYPE_DATA_LOCATION_IS_ADDR (type))
+ *address_return = TYPE_DATA_LOCATION_ADDR (type);
+ else if (TYPE_DATA_LOCATION_DWARF_BLOCK (type) != NULL)
+ *address_return
+ = dwarf_locexpr_baton_eval (TYPE_DATA_LOCATION_DWARF_BLOCK (type));
+
+ return type;
+}
+
/* Helper function for value_at, value_at_lazy, and value_at_lazy_stack. */
static struct value *
@@ -1011,12 +1071,20 @@ value_fetch_lazy (struct value *val)
}
else if (VALUE_LVAL (val) == lval_memory)
{
- CORE_ADDR addr = value_address (val);
- int length = TYPE_LENGTH (check_typedef (value_enclosing_type (val)));
+ CORE_ADDR addr = value_raw_address (val);
- if (length)
- read_value_memory (val, 0, value_stack (val),
- addr, value_contents_all_raw (val), length);
+ if (object_address_get_data (value_type (val), &addr))
+ {
+ struct type *type = value_enclosing_type (val);
+ int length = TYPE_LENGTH (check_typedef (type));
+
+ if (length)
+ {
+ addr += value_offset (val);
+ read_value_memory (val, 0, value_stack (val),
+ addr, value_contents_all_raw (val), length);
+ }
+ }
}
else if (VALUE_LVAL (val) == lval_register)
{
@@ -1528,7 +1596,18 @@ address_of_variable (struct symbol *var, struct block *b)
if ((VALUE_LVAL (val) == lval_memory && value_lazy (val))
|| TYPE_CODE (type) == TYPE_CODE_FUNC)
{
- CORE_ADDR addr = value_address (val);
+ CORE_ADDR addr;
+
+ if (VALUE_LVAL (val) == lval_memory)
+ {
+ addr = value_raw_address (val);
+ if (!object_address_get_data (type, &addr))
+ error (_("Can't take address of memory lvalue \"%s\"."),
+ SYMBOL_PRINT_NAME (var));
+ set_value_address (val, addr);
+ }
+
+ addr = value_address (val);
return value_from_pointer (lookup_pointer_type (type), addr);
}
@@ -1635,6 +1714,7 @@ struct value *
value_coerce_array (struct value *arg1)
{
struct type *type = check_typedef (value_type (arg1));
+ CORE_ADDR address;
/* If the user tries to do something requiring a pointer with an
array that has not yet been pushed to the target, then this would
@@ -1644,8 +1724,12 @@ value_coerce_array (struct value *arg1)
if (VALUE_LVAL (arg1) != lval_memory)
error (_("Attempt to take address of value not located in memory."));
+ address = value_raw_address (arg1);
+ if (!object_address_get_data (type, &address))
+ error (_("Attempt to take address of non-valid value."));
+
return value_from_pointer (lookup_pointer_type (TYPE_TARGET_TYPE (type)),
- value_address (arg1));
+ address + value_offset (arg1));
}
/* Given a value which is a function, return a value which is a pointer
@@ -3688,6 +3772,8 @@ value_slice (struct value *array, int lowbound, int length)
TYPE_TARGET_TYPE (range_type),
lowbound,
lowbound + length - 1);
+ TYPE_BYTE_STRIDE (slice_range_type) = TYPE_BYTE_STRIDE (range_type);
+
if (TYPE_CODE (array_type) == TYPE_CODE_BITSTRING)
{
int i;
diff --git a/gdb/valprint.c b/gdb/valprint.c
index 286ef9e..1fe58b1 100644
--- a/gdb/valprint.c
+++ b/gdb/valprint.c
@@ -36,6 +36,7 @@
#include "dfp.h"
#include "python/python.h"
#include "ada-lang.h"
+#include "dwarf2loc.h"
#include <errno.h>
@@ -239,7 +240,6 @@ scalar_type_p (struct type *type)
case TYPE_CODE_STRUCT:
case TYPE_CODE_UNION:
case TYPE_CODE_SET:
- case TYPE_CODE_STRING:
case TYPE_CODE_BITSTRING:
return 0;
default:
@@ -1193,6 +1193,7 @@ val_print_array_elements (struct type *type,
{
unsigned int things_printed = 0;
unsigned len;
+ struct type *saved_type = type;
struct type *elttype, *index_type;
unsigned eltlen;
/* Position of the array element we are examining to see
@@ -1201,9 +1202,33 @@ val_print_array_elements (struct type *type,
/* Number of repetitions we have detected so far. */
unsigned int reps;
LONGEST low_bound, high_bound;
+ struct cleanup *back_to;
+ CORE_ADDR saved_address = address;
+
+ back_to = make_cleanup (null_cleanup, 0);
+ type = object_address_get_data (type, &address);
+ if (!type)
+ {
+ fputs_filtered (object_address_data_not_valid (type), stream);
+ do_cleanups (back_to);
+ return;
+ }
+ if (address != saved_address)
+ {
+ size_t length = TYPE_LENGTH (type);
- elttype = TYPE_TARGET_TYPE (type);
- eltlen = TYPE_LENGTH (check_typedef (elttype));
+ valaddr = xmalloc (length);
+ make_cleanup (xfree, (gdb_byte *) valaddr);
+ read_memory (address, (gdb_byte *) valaddr, length);
+ }
+
+ /* Skip typedefs but do not resolve TYPE_DYNAMIC. */
+ elttype = saved_type;
+ while (TYPE_CODE (elttype) == TYPE_CODE_TYPEDEF)
+ elttype = TYPE_TARGET_TYPE (elttype);
+ elttype = TYPE_TARGET_TYPE (elttype);
+
+ eltlen = TYPE_ARRAY_BYTE_STRIDE_VALUE (type);
index_type = TYPE_INDEX_TYPE (type);
if (get_array_bounds (type, &low_bound, &high_bound))
@@ -1284,6 +1309,8 @@ val_print_array_elements (struct type *type,
{
fprintf_filtered (stream, "...");
}
+
+ do_cleanups (back_to);
}
/* Read LEN bytes of target memory at address MEMADDR, placing the
diff --git a/gdb/value.c b/gdb/value.c
index 2acb1df..abe774e 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -43,6 +43,7 @@
#include "python/python.h"
#include <ctype.h>
#include "tracepoint.h"
+#include "observer.h"
/* Prototypes for exported functions. */
@@ -1339,12 +1340,15 @@ void
set_value_component_location (struct value *component,
const struct value *whole)
{
+ CORE_ADDR addr;
+
if (whole->lval == lval_internalvar)
VALUE_LVAL (component) = lval_internalvar_component;
else
VALUE_LVAL (component) = whole->lval;
component->location = whole->location;
+
if (whole->lval == lval_computed)
{
struct lval_funcs *funcs = whole->location.computed.funcs;
@@ -1352,6 +1356,12 @@ set_value_component_location (struct value *component,
if (funcs->copy_closure)
component->location.computed.closure = funcs->copy_closure (whole);
}
+
+ addr = value_raw_address (component);
+ object_address_get_data (value_type (whole), &addr);
+ if (component->lval != lval_internalvar
+ && component->lval != lval_internalvar_component)
+ set_value_address (component, addr);
}
@@ -1485,6 +1495,31 @@ show_values (char *num_exp, int from_tty)
num_exp[1] = '\0';
}
}
+
+/* Sanity check for memory leaks and proper types reference counting. */
+
+static void
+value_history_cleanup (void *unused)
+{
+ while (value_history_chain)
+ {
+ struct value_history_chunk *chunk = value_history_chain;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE (chunk->values); i++)
+ value_free (chunk->values[i]);
+
+ value_history_chain = chunk->next;
+ xfree (chunk);
+ }
+ value_history_count = 0;
+
+ /* Free the unreferenced types above. */
+ free_all_values ();
+#if 0
+ free_all_types ();
+#endif
+}
/* Internal variables. These are variables within the debugger
that hold values assigned by debugger commands.
@@ -1530,7 +1565,14 @@ struct internalvar
struct value *value;
/* The call-back routine used with INTERNALVAR_MAKE_VALUE. */
- internalvar_make_value make_value;
+ struct
+ {
+ /* The functions to call. */
+ const struct internalvar_funcs *functions;
+
+ /* The function's user-data. */
+ void *data;
+ } make_value;
/* The internal function used with INTERNALVAR_FUNCTION. */
struct
@@ -1629,18 +1671,37 @@ create_internalvar (const char *name)
/* Create an internal variable with name NAME and register FUN as the
function that value_of_internalvar uses to create a value whenever
this variable is referenced. NAME should not normally include a
- dollar sign. */
+ dollar sign. DATA is passed uninterpreted to FUN when it is
+ called. CLEANUP, if not NULL, is called when the internal variable
+ is destroyed. It is passed DATA as its only argument. */
struct internalvar *
-create_internalvar_type_lazy (char *name, internalvar_make_value fun)
+create_internalvar_type_lazy (const char *name,
+ const struct internalvar_funcs *funcs,
+ void *data)
{
struct internalvar *var = create_internalvar (name);
var->kind = INTERNALVAR_MAKE_VALUE;
- var->u.make_value = fun;
+ var->u.make_value.functions = funcs;
+ var->u.make_value.data = data;
return var;
}
+int
+compile_internalvar_to_ax (struct internalvar *var,
+ struct agent_expr *expr,
+ struct axs_value *value)
+{
+ if (var->kind != INTERNALVAR_MAKE_VALUE
+ || var->u.make_value.functions->compile_to_ax == NULL)
+ return 0;
+
+ var->u.make_value.functions->compile_to_ax (var, expr, value,
+ var->u.make_value.data);
+ return 1;
+}
+
/* Look up an internal variable with name NAME. NAME should not
normally include a dollar sign.
@@ -1713,7 +1774,8 @@ value_of_internalvar (struct gdbarch *gdbarch, struct internalvar *var)
break;
case INTERNALVAR_MAKE_VALUE:
- val = (*var->u.make_value) (gdbarch, var);
+ val = (*var->u.make_value.functions->make_value) (gdbarch, var,
+ var->u.make_value.data);
break;
default:
@@ -1909,6 +1971,11 @@ clear_internalvar (struct internalvar *var)
xfree (var->u.string);
break;
+ case INTERNALVAR_MAKE_VALUE:
+ if (var->u.make_value.functions->destroy != NULL)
+ var->u.make_value.functions->destroy (var->u.make_value.data);
+ break;
+
default:
break;
}
@@ -1963,6 +2030,38 @@ call_internal_function (struct gdbarch *gdbarch,
return (*ifn->handler) (gdbarch, language, ifn->cookie, argc, argv);
}
+#if 0
+/* Call type_mark_used for any TYPEs referenced from this GDB source file. */
+
+static void
+value_types_mark_used (void)
+{
+ struct internalvar *var;
+ struct value_history_chunk *chunk;
+
+ for (var = internalvars; var != NULL; var = var->next)
+ switch (var->kind)
+ {
+ case INTERNALVAR_VALUE:
+ type_mark_used (value_type (var->u.value));
+ break;
+
+ case INTERNALVAR_INTEGER:
+ type_mark_used (var->u.integer.type);
+ break;
+ }
+
+ for (chunk = value_history_chain; chunk != NULL; chunk = chunk->next)
+ {
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE (chunk->values); i++)
+ if (chunk->values[i])
+ type_mark_used (value_type (chunk->values[i]));
+ }
+}
+#endif
+
/* The 'function' command. This does nothing -- it is just a
placeholder to let "help function NAME" work. This is also used as
the implementation of the sub-command that is created when
@@ -2010,11 +2109,10 @@ preserve_one_value (struct value *value, struct objfile *objfile,
htab_t copied_types)
{
if (TYPE_OBJFILE (value->type) == objfile)
- value->type = copy_type_recursive (objfile, value->type, copied_types);
+ value->type = copy_type_recursive (value->type, copied_types);
if (TYPE_OBJFILE (value->enclosing_type) == objfile)
- value->enclosing_type = copy_type_recursive (objfile,
- value->enclosing_type,
+ value->enclosing_type = copy_type_recursive (value->enclosing_type,
copied_types);
}
@@ -2029,7 +2127,7 @@ preserve_one_internalvar (struct internalvar *var, struct objfile *objfile,
case INTERNALVAR_INTEGER:
if (var->u.integer.type && TYPE_OBJFILE (var->u.integer.type) == objfile)
var->u.integer.type
- = copy_type_recursive (objfile, var->u.integer.type, copied_types);
+ = copy_type_recursive (var->u.integer.type, copied_types);
break;
case INTERNALVAR_VALUE:
@@ -3047,7 +3145,24 @@ value_from_history_ref (char *h, char **endp)
struct value *
coerce_ref (struct value *arg)
{
- struct type *value_type_arg_tmp = check_typedef (value_type (arg));
+ struct type *value_type_arg_tmp;
+
+ if (TYPE_DYNAMIC (value_type (arg)))
+ {
+ struct cleanup *cleanups = make_cleanup (null_cleanup, NULL);
+ CORE_ADDR address;
+
+ value_type_arg_tmp = value_type (arg);
+ address = value_raw_address (arg);
+ value_type_arg_tmp = object_address_get_data (value_type_arg_tmp,
+ &address);
+ if (! value_type_arg_tmp)
+ error (_("Attempt to coerce non-valid value."));
+ arg = value_at_lazy (value_type_arg_tmp, address);
+ do_cleanups (cleanups);
+ }
+ else
+ value_type_arg_tmp = check_typedef (value_type (arg));
if (TYPE_CODE (value_type_arg_tmp) == TYPE_CODE_REF)
arg = value_at_lazy (TYPE_TARGET_TYPE (value_type_arg_tmp),
@@ -3145,4 +3260,10 @@ VARIABLE is already initialized."));
add_prefix_cmd ("function", no_class, function_command, _("\
Placeholder command for showing help on convenience functions."),
&functionlist, "function ", 0, &cmdlist);
+
+ make_final_cleanup (value_history_cleanup, NULL);
+
+#if 0
+ observer_attach_mark_used (value_types_mark_used);
+#endif
}
diff --git a/gdb/value.h b/gdb/value.h
index 0889cef..4b51a4a 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -473,6 +473,10 @@ extern struct value *value_from_decfloat (struct type *type,
const gdb_byte *decbytes);
extern struct value *value_from_history_ref (char *, char **);
+extern const char *object_address_data_not_valid (struct type *type);
+extern struct type *object_address_get_data (struct type *type,
+ CORE_ADDR *address_return);
+
extern struct value *value_at (struct type *type, CORE_ADDR addr);
extern struct value *value_at_lazy (struct type *type, CORE_ADDR addr);
@@ -697,10 +701,52 @@ extern struct internalvar *lookup_only_internalvar (const char *name);
extern struct internalvar *create_internalvar (const char *name);
-typedef struct value * (*internalvar_make_value) (struct gdbarch *,
- struct internalvar *);
+/* An internalvar can be dynamically computed by supplying a vector of
+ function pointers to perform various operations. */
+
+struct internalvar_funcs
+{
+ /* Compute the value of the variable. The DATA argument passed to
+ the function is the same argument that was passed to
+ `create_internalvar_type_lazy'. */
+
+ struct value *(*make_value) (struct gdbarch *arch,
+ struct internalvar *var,
+ void *data);
+
+ /* Update the agent expression EXPR with bytecode to compute the
+ value. VALUE is the agent value we are updating. The DATA
+ argument passed to this function is the same argument that was
+ passed to `create_internalvar_type_lazy'. If this pointer is
+ NULL, then the internalvar cannot be compiled to an agent
+ expression. */
+
+ void (*compile_to_ax) (struct internalvar *var,
+ struct agent_expr *expr,
+ struct axs_value *value,
+ void *data);
+
+ /* If non-NULL, this is called to destroy DATA. The DATA argument
+ passed to this function is the same argument that was passed to
+ `create_internalvar_type_lazy'. */
+
+ void (*destroy) (void *data);
+};
+
extern struct internalvar *
- create_internalvar_type_lazy (char *name, internalvar_make_value fun);
+create_internalvar_type_lazy (const char *name,
+ const struct internalvar_funcs *funcs,
+ void *data);
+
+/* Compile an internal variable to an agent expression. VAR is the
+ variable to compile; EXPR and VALUE are the agent expression we are
+ updating. This will return 0 if there is no known way to compile
+ VAR, and 1 if VAR was successfully compiled. It may also throw an
+ exception on error. */
+
+extern int compile_internalvar_to_ax (struct internalvar *var,
+ struct agent_expr *expr,
+ struct axs_value *value);
extern struct internalvar *lookup_internalvar (const char *name);
diff --git a/gdb/windows-tdep.c b/gdb/windows-tdep.c
index 31ddd14..b36e4ca 100644
--- a/gdb/windows-tdep.c
+++ b/gdb/windows-tdep.c
@@ -268,7 +268,7 @@ static struct lval_funcs tlb_value_funcs =
if there's no object available. */
static struct value *
-tlb_make_value (struct gdbarch *gdbarch, struct internalvar *var)
+tlb_make_value (struct gdbarch *gdbarch, struct internalvar *var, void *ignore)
{
if (target_has_stack && !ptid_equal (inferior_ptid, null_ptid))
{
@@ -425,6 +425,13 @@ init_w32_command_list (void)
}
}
+static const struct internalvar_funcs tlb_funcs =
+{
+ tlb_make_value,
+ NULL,
+ NULL
+};
+
void
_initialize_windows_tdep (void)
{
@@ -451,5 +458,5 @@ even if their meaning is unknown."),
value with a void typed value, and when we get here, gdbarch
isn't initialized yet. At this point, we're quite sure there
isn't another convenience variable of the same name. */
- create_internalvar_type_lazy ("_tlb", tlb_make_value);
+ create_internalvar_type_lazy ("_tlb", &tlb_funcs, NULL);
}
diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c
index 081080c..f71dbfe 100644
--- a/gdb/xcoffread.c
+++ b/gdb/xcoffread.c
@@ -3090,6 +3090,7 @@ static const struct sym_fns xcoff_sym_fns =
default_symfile_segments, /* Get segment information from a file. */
aix_process_linenos,
default_symfile_relocate, /* Relocate a debug section. */
+ NULL, /* sym_probe_fns */
&psym_functions
};