mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-11-16 12:34:43 +00:00
Compare commits
66 Commits
users/nalc
...
gdb-15.1-r
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7b20890ad6 | ||
|
|
35ad5708a7 | ||
|
|
ef5930bd0f | ||
|
|
f7e429d581 | ||
|
|
2de28d2f45 | ||
|
|
cec2e207d0 | ||
|
|
edd3f7be25 | ||
|
|
041fb9da7d | ||
|
|
b1f7227b7e | ||
|
|
0c7862ac50 | ||
|
|
f6c0e1bad2 | ||
|
|
d36933683a | ||
|
|
d417a64fc2 | ||
|
|
8d134aa67f | ||
|
|
d432cd83c0 | ||
|
|
476ed517b2 | ||
|
|
3eb137638e | ||
|
|
a21a737e01 | ||
|
|
1396b91045 | ||
|
|
390359aea1 | ||
|
|
72429c2a17 | ||
|
|
dd6d09fd2b | ||
|
|
ccda71a89a | ||
|
|
e7b3fd348f | ||
|
|
f33b87956f | ||
|
|
7d3de2ad64 | ||
|
|
1aa3b72f07 | ||
|
|
9c6d76c0d7 | ||
|
|
bdda01fd9b | ||
|
|
db432c3d50 | ||
|
|
af91ec845e | ||
|
|
7738a8af9d | ||
|
|
44709ad8f5 | ||
|
|
d1f2ec5e93 | ||
|
|
a49df3daea | ||
|
|
4239c6015a | ||
|
|
f41400ee71 | ||
|
|
0c7da7665f | ||
|
|
2681e24698 | ||
|
|
02be73cce7 | ||
|
|
05187655ae | ||
|
|
48db4a8344 | ||
|
|
2feb7c1810 | ||
|
|
3504ea2946 | ||
|
|
8fb41483be | ||
|
|
8215789c47 | ||
|
|
3e61e9a527 | ||
|
|
9b1ed1f3b5 | ||
|
|
a89164f88c | ||
|
|
116e8a3821 | ||
|
|
3ad94add7f | ||
|
|
8af148e476 | ||
|
|
1e1cc01596 | ||
|
|
ec7683e3d7 | ||
|
|
80fba8a24f | ||
|
|
5fcf2ea766 | ||
|
|
909e567305 | ||
|
|
8b69689d8b | ||
|
|
9c2db7a3c7 | ||
|
|
97b31937d6 | ||
|
|
d5185bee0b | ||
|
|
6aabfa4522 | ||
|
|
5194ca4da1 | ||
|
|
d2c4f42000 | ||
|
|
85f8f79ea8 | ||
|
|
38e47144a5 |
@@ -16,7 +16,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Controls whether to enable development-mode features by default.
|
||||
development=true
|
||||
development=false
|
||||
|
||||
# Indicate whether this is a release branch.
|
||||
experimental=true
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
In releases, the date is not included in either version strings or
|
||||
sonames. */
|
||||
#define BFD_VERSION_DATE 20240526
|
||||
#define BFD_VERSION_DATE 20240707
|
||||
#define BFD_VERSION @bfd_version@
|
||||
#define BFD_VERSION_STRING @bfd_version_package@ @bfd_version_string@
|
||||
#define REPORT_BUGS_TO @report_bugs_to@
|
||||
|
||||
2
gdb/NEWS
2
gdb/NEWS
@@ -1,7 +1,7 @@
|
||||
What has changed in GDB?
|
||||
(Organized release by release)
|
||||
|
||||
*** Changes since GDB 14
|
||||
*** Changes in GDB 15
|
||||
|
||||
* The MPX commands "show/set mpx bound" have been deprecated, as Intel
|
||||
listed MPX as removed in 2019.
|
||||
|
||||
@@ -78,12 +78,6 @@ public:
|
||||
|
||||
int can_do_single_step () override;
|
||||
|
||||
/* Override the GNU/Linux inferior startup hook. */
|
||||
void post_startup_inferior (ptid_t) override;
|
||||
|
||||
/* Override the GNU/Linux post attach hook. */
|
||||
void post_attach (int pid) override;
|
||||
|
||||
/* These three defer to common nat/ code. */
|
||||
void low_new_thread (struct lwp_info *lp) override
|
||||
{ aarch64_linux_new_thread (lp); }
|
||||
@@ -93,6 +87,7 @@ public:
|
||||
{ aarch64_linux_prepare_to_resume (lp); }
|
||||
|
||||
void low_new_fork (struct lwp_info *parent, pid_t child_pid) override;
|
||||
void low_init_process (pid_t pid) override;
|
||||
void low_forget_process (pid_t pid) override;
|
||||
|
||||
/* Add our siginfo layout converter. */
|
||||
@@ -844,29 +839,18 @@ ps_get_thread_area (struct ps_prochandle *ph,
|
||||
}
|
||||
|
||||
|
||||
/* Implement the virtual inf_ptrace_target::post_startup_inferior method. */
|
||||
/* Implement the "low_init_process" target_ops method. */
|
||||
|
||||
void
|
||||
aarch64_linux_nat_target::post_startup_inferior (ptid_t ptid)
|
||||
{
|
||||
low_forget_process (ptid.pid ());
|
||||
aarch64_linux_get_debug_reg_capacity (ptid.pid ());
|
||||
linux_nat_target::post_startup_inferior (ptid);
|
||||
}
|
||||
|
||||
/* Implement the "post_attach" target_ops method. */
|
||||
|
||||
void
|
||||
aarch64_linux_nat_target::post_attach (int pid)
|
||||
aarch64_linux_nat_target::low_init_process (pid_t pid)
|
||||
{
|
||||
low_forget_process (pid);
|
||||
/* Set the hardware debug register capacity. If
|
||||
aarch64_linux_get_debug_reg_capacity is not called
|
||||
(as it is in aarch64_linux_child_post_startup_inferior) then
|
||||
software watchpoints will be used instead of hardware
|
||||
watchpoints when attaching to a target. */
|
||||
/* Set the hardware debug register capacity. This requires the process to be
|
||||
ptrace-stopped, otherwise detection will fail and software watchpoints will
|
||||
be used instead of hardware. If we allow this to be done lazily, we
|
||||
cannot guarantee that it's called when the process is ptrace-stopped, so
|
||||
do it now. */
|
||||
aarch64_linux_get_debug_reg_capacity (pid);
|
||||
linux_nat_target::post_attach (pid);
|
||||
}
|
||||
|
||||
/* Implement the "read_description" target_ops method. */
|
||||
|
||||
@@ -3808,10 +3808,12 @@ aarch64_displaced_step_copy_insn (struct gdbarch *gdbarch,
|
||||
if (aarch64_decode_insn (insn, &inst, 1, NULL) != 0)
|
||||
return NULL;
|
||||
|
||||
/* Look for a Load Exclusive instruction which begins the sequence. */
|
||||
if (inst.opcode->iclass == ldstexcl && bit (insn, 22))
|
||||
/* Look for a Load Exclusive instruction which begins the sequence,
|
||||
or for a MOPS instruction. */
|
||||
if ((inst.opcode->iclass == ldstexcl && bit (insn, 22))
|
||||
|| AARCH64_CPU_HAS_FEATURE (*inst.opcode->avariant, MOPS))
|
||||
{
|
||||
/* We can't displaced step atomic sequences. */
|
||||
/* We can't displaced step atomic sequences nor MOPS instructions. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -5186,6 +5188,71 @@ aarch64_record_asimd_load_store (aarch64_insn_decode_record *aarch64_insn_r)
|
||||
return AARCH64_RECORD_SUCCESS;
|
||||
}
|
||||
|
||||
/* Record handler for Memory Copy and Memory Set instructions. */
|
||||
|
||||
static unsigned int
|
||||
aarch64_record_memcopy_memset (aarch64_insn_decode_record *aarch64_insn_r)
|
||||
{
|
||||
if (record_debug)
|
||||
debug_printf ("Process record: memory copy and memory set\n");
|
||||
|
||||
uint8_t op1 = bits (aarch64_insn_r->aarch64_insn, 22, 23);
|
||||
uint8_t op2 = bits (aarch64_insn_r->aarch64_insn, 12, 15);
|
||||
uint32_t reg_rd = bits (aarch64_insn_r->aarch64_insn, 0, 4);
|
||||
uint32_t reg_rn = bits (aarch64_insn_r->aarch64_insn, 5, 9);
|
||||
uint32_t record_buf[3];
|
||||
uint64_t record_buf_mem[4];
|
||||
|
||||
if (op1 == 3 && op2 > 11)
|
||||
/* Unallocated instructions. */
|
||||
return AARCH64_RECORD_UNKNOWN;
|
||||
|
||||
/* Set instructions have two registers and one memory region to be
|
||||
recorded. */
|
||||
record_buf[0] = reg_rd;
|
||||
record_buf[1] = reg_rn;
|
||||
aarch64_insn_r->reg_rec_count = 2;
|
||||
|
||||
ULONGEST dest_addr;
|
||||
regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rd, &dest_addr);
|
||||
|
||||
LONGEST length;
|
||||
regcache_raw_read_signed (aarch64_insn_r->regcache, reg_rn, &length);
|
||||
|
||||
/* In one of the algorithm options a processor can implement, the length
|
||||
in Rn has an inverted sign. */
|
||||
if (length < 0)
|
||||
length *= -1;
|
||||
|
||||
record_buf_mem[0] = length;
|
||||
record_buf_mem[1] = dest_addr;
|
||||
aarch64_insn_r->mem_rec_count = 1;
|
||||
|
||||
if (op1 != 3)
|
||||
{
|
||||
/* Copy instructions have an additional register and an additional
|
||||
memory region to be recorded. */
|
||||
uint32_t reg_rs = bits (aarch64_insn_r->aarch64_insn, 16, 20);
|
||||
|
||||
record_buf[2] = reg_rs;
|
||||
aarch64_insn_r->reg_rec_count++;
|
||||
|
||||
ULONGEST source_addr;
|
||||
regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rs,
|
||||
&source_addr);
|
||||
|
||||
record_buf_mem[2] = length;
|
||||
record_buf_mem[3] = source_addr;
|
||||
aarch64_insn_r->mem_rec_count++;
|
||||
}
|
||||
|
||||
MEM_ALLOC (aarch64_insn_r->aarch64_mems, aarch64_insn_r->mem_rec_count,
|
||||
record_buf_mem);
|
||||
REG_ALLOC (aarch64_insn_r->aarch64_regs, aarch64_insn_r->reg_rec_count,
|
||||
record_buf);
|
||||
return AARCH64_RECORD_SUCCESS;
|
||||
}
|
||||
|
||||
/* Record handler for load and store instructions. */
|
||||
|
||||
static unsigned int
|
||||
@@ -5463,6 +5530,10 @@ aarch64_record_load_store (aarch64_insn_decode_record *aarch64_insn_r)
|
||||
if (insn_bits10_11 == 0x01 || insn_bits10_11 == 0x03)
|
||||
record_buf[aarch64_insn_r->reg_rec_count++] = reg_rn;
|
||||
}
|
||||
/* Memory Copy and Memory Set instructions. */
|
||||
else if ((insn_bits24_27 & 1) == 1 && insn_bits28_29 == 1
|
||||
&& insn_bits10_11 == 1 && !insn_bit21)
|
||||
return aarch64_record_memcopy_memset (aarch64_insn_r);
|
||||
/* Advanced SIMD load/store instructions. */
|
||||
else
|
||||
return aarch64_record_asimd_load_store (aarch64_insn_r);
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
%{
|
||||
|
||||
#include <ctype.h>
|
||||
#include <unordered_map>
|
||||
#include "expression.h"
|
||||
#include "value.h"
|
||||
#include "parser-defs.h"
|
||||
|
||||
@@ -103,6 +103,7 @@ public:
|
||||
|
||||
/* Handle process creation and exit. */
|
||||
void low_new_fork (struct lwp_info *parent, pid_t child_pid) override;
|
||||
void low_init_process (pid_t pid) override;
|
||||
void low_forget_process (pid_t pid) override;
|
||||
};
|
||||
|
||||
@@ -805,6 +806,19 @@ arm_linux_process_info_get (pid_t pid)
|
||||
return proc;
|
||||
}
|
||||
|
||||
/* Implement the "low_init_process" target_ops method. */
|
||||
|
||||
void
|
||||
arm_linux_nat_target::low_init_process (pid_t pid)
|
||||
{
|
||||
/* Set the hardware debug register capacity. This requires the process to be
|
||||
ptrace-stopped, otherwise detection will fail and software watchpoints will
|
||||
be used instead of hardware. If we allow this to be done lazily, we
|
||||
cannot guarantee that it's called when the process is ptrace-stopped, so
|
||||
do it now. */
|
||||
arm_linux_get_hwbp_cap ();
|
||||
}
|
||||
|
||||
/* Called whenever GDB is no longer debugging process PID. It deletes
|
||||
data structures that keep track of debug register state. */
|
||||
|
||||
|
||||
@@ -287,10 +287,10 @@ cp_search_static_and_baseclasses (const char *name,
|
||||
struct type *scope_type = scope_sym.symbol->type ();
|
||||
|
||||
/* If the scope is a function/method, then look up NESTED as a local
|
||||
static variable. E.g., "print 'function()::static_var'". */
|
||||
static variable or type. E.g., "print 'function()::static_var'". */
|
||||
if ((scope_type->code () == TYPE_CODE_FUNC
|
||||
|| scope_type->code () == TYPE_CODE_METHOD)
|
||||
&& (domain & SEARCH_VAR_DOMAIN) != 0)
|
||||
&& (domain & (SEARCH_VAR_DOMAIN | SEARCH_TYPE_DOMAIN)) != 0)
|
||||
return lookup_symbol (nested, scope_sym.symbol->value_block (),
|
||||
domain, NULL);
|
||||
|
||||
|
||||
@@ -658,17 +658,30 @@ annotate/index.html: $(ANNOTATE_DOC_FILES)
|
||||
-I $(srcdir) \
|
||||
$(srcdir)/annotate.texinfo
|
||||
|
||||
# Man pages
|
||||
%.pod : gdb.texinfo $(GDB_DOC_FILES)
|
||||
$(ECHO_TEXI2POD) $(TEXI2POD) $(MANCONF) -D$* < $(srcdir)/gdb.texinfo > $@
|
||||
|
||||
$(MAN1S) : %.1 : %.pod $(GDB_DOC_FILES)
|
||||
# Man pages. The TEXI2POD and TEXI2MAN steps are performed within a
|
||||
# single recipe to support how we distribute GDB releases. A release
|
||||
# includes the .1 and .5 man pages in the source tree, but not the
|
||||
# .pod files.
|
||||
#
|
||||
# When building and installing a release of GDB it should not be
|
||||
# necessary to rebuild the .1 or .5 man page files, nor should it be
|
||||
# necessary to rebuild the .pod files.
|
||||
#
|
||||
# If we split the .pod creation from the creation of the .1 and .5
|
||||
# pages, then the .pod files must become a dependency, this will
|
||||
# trigger an attempt to rebuild these files while building and
|
||||
# installing a release of GDB, which is something we don't want.
|
||||
$(MAN1S) : %.1 : $(GDB_DOC_FILES)
|
||||
$(ECHO_TEXI2POD) $(TEXI2POD) $(MANCONF) -D$* < $(srcdir)/gdb.texinfo > $*.pod
|
||||
$(ECHO_TEXI2MAN) ($(POD2MAN1) $*.pod | sed -e '/^.if n .na/d' > $@.T$$$$ && \
|
||||
mv -f $@.T$$$$ $@) || (rm -f $@.T$$$$ && exit 1)
|
||||
$(SILENCE) rm -f $*.pod
|
||||
|
||||
$(MAN5S) : %.5 : %.pod $(GDB_DOC_FILES)
|
||||
$(ECHO_TEXI2MAN) ($(POD2MAN1) $*.pod | sed -e '/^.if n .na/d' > $@.T$$$$ && \
|
||||
$(MAN5S) : %.5 : $(GDB_DOC_FILES)
|
||||
$(ECHO_TEXI2POD) $(TEXI2POD) $(MANCONF) -D$* < $(srcdir)/gdb.texinfo > $*.pod
|
||||
$(ECHO_TEXI2MAN) ($(POD2MAN5) $*.pod | sed -e '/^.if n .na/d' > $@.T$$$$ && \
|
||||
mv -f $@.T$$$$ $@) || (rm -f $@.T$$$$ && exit 1)
|
||||
$(SILENCE) rm -f $*.pod
|
||||
|
||||
force:
|
||||
|
||||
|
||||
@@ -528,7 +528,7 @@ objfile_find_memory_regions (struct target_ops *self,
|
||||
find_memory_region_ftype func, void *obfd)
|
||||
{
|
||||
/* Use objfile data to create memory sections. */
|
||||
bfd_vma temp_bottom, temp_top;
|
||||
bfd_vma temp_bottom = 0, temp_top = 0;
|
||||
|
||||
/* Call callback function for each objfile section. */
|
||||
for (objfile *objfile : current_program_space->objfiles ())
|
||||
|
||||
@@ -76,8 +76,19 @@ typedef wint_t gdb_wint_t;
|
||||
We exploit this fact in the hope that there are hosts that define
|
||||
this but which do not support "wchar_t" as an encoding argument to
|
||||
iconv_open. We put the endianness into the encoding name to avoid
|
||||
hosts that emit a BOM when the unadorned name is used. */
|
||||
#if defined (__STDC_ISO_10646__)
|
||||
hosts that emit a BOM when the unadorned name is used.
|
||||
|
||||
Also, on version 14 macOS 'Sonoma', the implementation of iconv was
|
||||
changed in such a way that breaks the way that gdb was using it.
|
||||
Specifically, using wchar_t as an intermediate encoding silently
|
||||
breaks when attempting to do character-by-character encoding.
|
||||
By using the intermediate_encoding function to choose a suitable
|
||||
encoding to put in the wchar_t, the iconv implementation behaves as
|
||||
we expect it to. Strictly speaking, this seems to be a bug in
|
||||
Sonoma specifically, but it is desirable for binaries built for
|
||||
older versions of macOS to still work on newer ones such as Sonoma,
|
||||
so there is no version check here for this workaround. */
|
||||
#if defined (__STDC_ISO_10646__) || defined (__APPLE__)
|
||||
#define USE_INTERMEDIATE_ENCODING_FUNCTION
|
||||
#define INTERMEDIATE_ENCODING intermediate_encoding ()
|
||||
const char *intermediate_encoding (void);
|
||||
|
||||
@@ -280,13 +280,13 @@ struct gdb_mpz
|
||||
gdb_mpz operator>> (unsigned long nbits) const
|
||||
{
|
||||
gdb_mpz result;
|
||||
mpz_tdiv_q_2exp (result.m_val, m_val, nbits);
|
||||
mpz_fdiv_q_2exp (result.m_val, m_val, nbits);
|
||||
return result;
|
||||
}
|
||||
|
||||
gdb_mpz &operator>>= (unsigned long nbits)
|
||||
{
|
||||
mpz_tdiv_q_2exp (m_val, m_val, nbits);
|
||||
mpz_fdiv_q_2exp (m_val, m_val, nbits);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
@@ -454,6 +454,12 @@ linux_init_ptrace_procfs (pid_t pid, int attached)
|
||||
linux_ptrace_init_warnings ();
|
||||
linux_proc_init_warnings ();
|
||||
proc_mem_file_is_writable ();
|
||||
|
||||
/* Let the arch-specific native code do any needed initialization.
|
||||
Some architectures need to call ptrace to check for hardware
|
||||
watchpoints support, etc. Call it now, when we know the tracee
|
||||
is ptrace-stopped. */
|
||||
linux_target->low_init_process (pid);
|
||||
}
|
||||
|
||||
linux_nat_target::~linux_nat_target ()
|
||||
|
||||
@@ -164,6 +164,12 @@ public:
|
||||
virtual void low_new_clone (struct lwp_info *parent, pid_t child_lwp)
|
||||
{}
|
||||
|
||||
/* The method to call, if any, when we have a new (from run/attach,
|
||||
not fork) process to debug. The process is ptrace-stopped when
|
||||
this is called. */
|
||||
virtual void low_init_process (pid_t pid)
|
||||
{}
|
||||
|
||||
/* The method to call, if any, when a process is no longer
|
||||
attached. */
|
||||
virtual void low_forget_process (pid_t pid)
|
||||
|
||||
@@ -545,6 +545,8 @@ struct ppc_linux_nat_target final : public linux_nat_target
|
||||
|
||||
void low_new_clone (struct lwp_info *, pid_t) override;
|
||||
|
||||
void low_init_process (pid_t pid) override;
|
||||
|
||||
void low_forget_process (pid_t pid) override;
|
||||
|
||||
void low_prepare_to_resume (struct lwp_info *) override;
|
||||
@@ -2705,6 +2707,19 @@ ppc_linux_nat_target::remove_watchpoint (CORE_ADDR addr, int len,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Implement the "low_init_process" target_ops method. */
|
||||
|
||||
void
|
||||
ppc_linux_nat_target::low_init_process (pid_t pid)
|
||||
{
|
||||
/* Set the hardware debug register capacity. This requires the process to be
|
||||
ptrace-stopped, otherwise detection will fail and software watchpoints will
|
||||
be used instead of hardware. If we allow this to be done lazily, we
|
||||
cannot guarantee that it's called when the process is ptrace-stopped, so
|
||||
do it now. */
|
||||
m_dreg_interface.detect (ptid_t (pid, pid));
|
||||
}
|
||||
|
||||
/* Clean up the per-process info associated with PID. When using the
|
||||
HWDEBUG interface, we also erase the per-thread state of installed
|
||||
debug registers for all the threads that belong to the group of PID.
|
||||
|
||||
@@ -667,12 +667,13 @@ disasmpy_info_read_memory (PyObject *self, PyObject *args, PyObject *kw)
|
||||
disasm_info_object *obj = (disasm_info_object *) self;
|
||||
DISASMPY_DISASM_INFO_REQUIRE_VALID (obj);
|
||||
|
||||
LONGEST length, offset = 0;
|
||||
gdb_py_longest length, offset = 0;
|
||||
gdb::unique_xmalloc_ptr<gdb_byte> buffer;
|
||||
static const char *keywords[] = { "length", "offset", nullptr };
|
||||
|
||||
if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "L|L", keywords,
|
||||
&length, &offset))
|
||||
if (!gdb_PyArg_ParseTupleAndKeywords (args, kw,
|
||||
GDB_PY_LL_ARG "|" GDB_PY_LL_ARG,
|
||||
keywords, &length, &offset))
|
||||
return nullptr;
|
||||
|
||||
/* The apparent address from which we are reading memory. Note that in
|
||||
@@ -849,13 +850,14 @@ gdbpy_disassembler::read_memory_func (bfd_vma memaddr, gdb_byte *buff,
|
||||
/* The DisassembleInfo.read_memory method expects an offset from the
|
||||
address stored within the DisassembleInfo object; calculate that
|
||||
offset here. */
|
||||
LONGEST offset = (LONGEST) memaddr - (LONGEST) obj->address;
|
||||
gdb_py_longest offset
|
||||
= (gdb_py_longest) memaddr - (gdb_py_longest) obj->address;
|
||||
|
||||
/* Now call the DisassembleInfo.read_memory method. This might have been
|
||||
overridden by the user. */
|
||||
gdbpy_ref<> result_obj (PyObject_CallMethod ((PyObject *) obj,
|
||||
"read_memory",
|
||||
"KL", len, offset));
|
||||
"I" GDB_PY_LL_ARG, len, offset));
|
||||
|
||||
/* Handle any exceptions. */
|
||||
if (result_obj == nullptr)
|
||||
|
||||
@@ -266,7 +266,7 @@ stpy_lazy_string_elt_type (lazy_string_object *lazy)
|
||||
{
|
||||
case TYPE_CODE_PTR:
|
||||
case TYPE_CODE_ARRAY:
|
||||
return realtype->target_type ();
|
||||
return check_typedef (realtype->target_type ());
|
||||
default:
|
||||
/* This is done to preserve existing behaviour. PR 20769.
|
||||
E.g., gdb.parse_and_eval("my_int_variable").lazy_string().type. */
|
||||
|
||||
73
gdb/testsuite/gdb.arch/aarch64-mops-single-step.c
Normal file
73
gdb/testsuite/gdb.arch/aarch64-mops-single-step.c
Normal file
@@ -0,0 +1,73 @@
|
||||
/* This file is part of GDB, the GNU debugger.
|
||||
|
||||
Copyright 2024 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/>. */
|
||||
|
||||
#define TEST_STRING "Just a test string."
|
||||
#define BUF_SIZE sizeof(TEST_STRING)
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
char source[BUF_SIZE] = TEST_STRING;
|
||||
char dest[BUF_SIZE];
|
||||
char *p, *q;
|
||||
long size, zero;
|
||||
|
||||
/* Note: The prfm instruction in the asm statements below is there just
|
||||
to allow the testcase to recognize when the PC is at the instruction
|
||||
right after the MOPS sequence. */
|
||||
|
||||
p = dest;
|
||||
size = sizeof (dest);
|
||||
zero = 0;
|
||||
/* Break memset. */
|
||||
/* memset implemented in MOPS instructions. */
|
||||
__asm__ volatile ("setp [%0]!, %1!, %2\n\t"
|
||||
"setm [%0]!, %1!, %2\n\t"
|
||||
"sete [%0]!, %1!, %2\n\t"
|
||||
"prfm pldl3keep, [%0, #0]\n\t"
|
||||
: "+&r"(p), "+&r"(size)
|
||||
: "r"(zero)
|
||||
: "memory");
|
||||
|
||||
p = dest;
|
||||
q = source;
|
||||
size = sizeof (dest);
|
||||
/* Break memcpy. */
|
||||
/* memcpy implemented in MOPS instructions. */
|
||||
__asm__ volatile ("cpyfp [%0]!, [%1]!, %2!\n\t"
|
||||
"cpyfm [%0]!, [%1]!, %2!\n\t"
|
||||
"cpyfe [%0]!, [%1]!, %2!\n\t"
|
||||
"prfm pldl3keep, [%0, #0]\n\t"
|
||||
: "+&r" (p), "+&r" (q), "+&r" (size)
|
||||
:
|
||||
: "memory");
|
||||
|
||||
p = dest;
|
||||
q = source;
|
||||
size = sizeof (dest);
|
||||
/* Break memmove. */
|
||||
/* memmove implemented in MOPS instructions. */
|
||||
__asm__ volatile ("cpyp [%0]!, [%1]!, %2!\n\t"
|
||||
"cpym [%0]!, [%1]!, %2!\n\t"
|
||||
"cpye [%0]!, [%1]!, %2!\n\t"
|
||||
"prfm pldl3keep, [%0, #0]\n\t"
|
||||
: "+&r" (p), "+&r" (q), "+&r" (size)
|
||||
:
|
||||
: "memory");
|
||||
|
||||
return 0;
|
||||
}
|
||||
98
gdb/testsuite/gdb.arch/aarch64-mops-single-step.exp
Normal file
98
gdb/testsuite/gdb.arch/aarch64-mops-single-step.exp
Normal file
@@ -0,0 +1,98 @@
|
||||
# Copyright 2024 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 file is part of the GDB testsuite.
|
||||
|
||||
# Test single stepping through MOPS (memory operations) instruction sequences.
|
||||
|
||||
require allow_aarch64_mops_tests
|
||||
|
||||
standard_testfile
|
||||
if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \
|
||||
[list debug additional_flags=-march=armv9.3-a]] } {
|
||||
return -1
|
||||
}
|
||||
|
||||
# If the inferior is rescheduled to another CPU while a main or epilogue
|
||||
# instruction is executed, the OS resets the inferior back to the prologue
|
||||
# instruction, so we need to allow for that possibility.
|
||||
proc step_through_sequence { prefix } {
|
||||
set count 0
|
||||
|
||||
while { [is_at_instruction ${prefix}p] == 1 && $count < 50 } {
|
||||
incr count
|
||||
|
||||
# The stepi output isn't useful to detect whether we stepped over
|
||||
# the instruction.
|
||||
gdb_test "stepi" "\[^\r\n\]+" "step over ${prefix}p"
|
||||
if { [is_at_instruction ${prefix}m] == 1 } {
|
||||
pass "stepped over ${prefix}p"
|
||||
} else {
|
||||
fail "stepped over ${prefix}e"
|
||||
return 0
|
||||
}
|
||||
|
||||
gdb_test "stepi" "\[^\r\n\]+" "step over ${prefix}m"
|
||||
if { [is_at_instruction ${prefix}e] == 1 } {
|
||||
pass "stepped over ${prefix}m"
|
||||
} elseif { [is_at_instruction ${prefix}p] == 1 } {
|
||||
# The inferior was rescheduled to another CPU.
|
||||
pass "${prefix}m: reset back to prologue"
|
||||
continue
|
||||
} else {
|
||||
fail "stepped over ${prefix}m"
|
||||
return 0
|
||||
}
|
||||
|
||||
gdb_test "stepi" "\[^\r\n\]+" "step over ${prefix}e"
|
||||
if { [is_at_instruction prfm] == 1 } {
|
||||
pass "stepped over ${prefix}e"
|
||||
return 1
|
||||
} elseif { [is_at_instruction ${prefix}p] == 1 } {
|
||||
# The inferior was rescheduled to another CPU.
|
||||
pass "${prefix}e: reset back to prologue"
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
fail "step through $prefix sequence"
|
||||
return 0
|
||||
}
|
||||
|
||||
if ![runto_main] {
|
||||
return -1
|
||||
}
|
||||
|
||||
gdb_breakpoint ${srcfile}:[gdb_get_line_number "Break memset"]
|
||||
gdb_breakpoint ${srcfile}:[gdb_get_line_number "Break memcpy"]
|
||||
gdb_breakpoint ${srcfile}:[gdb_get_line_number "Break memmove"]
|
||||
|
||||
gdb_continue_to_breakpoint "memset breakpoint"
|
||||
|
||||
if { [arrive_at_instruction setp] } {
|
||||
step_through_sequence set
|
||||
}
|
||||
|
||||
gdb_continue_to_breakpoint "memcpy breakpoint"
|
||||
|
||||
if { [arrive_at_instruction cpyfp] } {
|
||||
step_through_sequence cpyf
|
||||
}
|
||||
|
||||
gdb_continue_to_breakpoint "memmove breakpoint"
|
||||
|
||||
if { [arrive_at_instruction cpyp] } {
|
||||
step_through_sequence cpy
|
||||
}
|
||||
66
gdb/testsuite/gdb.arch/aarch64-mops-watchpoint.c
Normal file
66
gdb/testsuite/gdb.arch/aarch64-mops-watchpoint.c
Normal file
@@ -0,0 +1,66 @@
|
||||
/* This test program is part of GDB, the GNU debugger.
|
||||
|
||||
Copyright 2024 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
|
||||
main (void)
|
||||
{
|
||||
char source[40] __attribute__ ((aligned (8)))
|
||||
= "This is a relatively long string...";
|
||||
char a[40] __attribute__ ((aligned (8)))
|
||||
= "String to be overwritten with zeroes";
|
||||
char b[40] __attribute__ ((aligned (8)))
|
||||
= "Another string to be memcopied...";
|
||||
char c[40] __attribute__ ((aligned (8)))
|
||||
= "Another string to be memmoved...";
|
||||
char *p, *q;
|
||||
long size, zero;
|
||||
|
||||
/* Break here. */
|
||||
p = a;
|
||||
size = sizeof (a);
|
||||
zero = 0;
|
||||
/* memset implemented in MOPS instructions. */
|
||||
__asm__ volatile ("setp [%0]!, %1!, %2\n\t"
|
||||
"setm [%0]!, %1!, %2\n\t"
|
||||
"sete [%0]!, %1!, %2\n\t"
|
||||
: "+&r"(p), "+&r"(size)
|
||||
: "r"(zero)
|
||||
: "memory");
|
||||
|
||||
p = b;
|
||||
q = source;
|
||||
size = sizeof (b);
|
||||
/* memmove implemented in MOPS instructions. */
|
||||
__asm__ volatile ("cpyp [%0]!, [%1]!, %2!\n\t"
|
||||
"cpym [%0]!, [%1]!, %2!\n\t"
|
||||
"cpye [%0]!, [%1]!, %2!\n\t"
|
||||
: "+&r" (p), "+&r" (q), "+&r" (size)
|
||||
:
|
||||
: "memory");
|
||||
p = c;
|
||||
q = source;
|
||||
size = sizeof (c);
|
||||
/* memcpy implemented in MOPS instructions. */
|
||||
__asm__ volatile ("cpyfp [%0]!, [%1]!, %2!\n\t"
|
||||
"cpyfm [%0]!, [%1]!, %2!\n\t"
|
||||
"cpyfe [%0]!, [%1]!, %2!\n\t"
|
||||
: "+&r" (p), "+&r" (q), "+&r" (size)
|
||||
:
|
||||
: "memory");
|
||||
|
||||
return 0;
|
||||
}
|
||||
79
gdb/testsuite/gdb.arch/aarch64-mops-watchpoint.exp
Normal file
79
gdb/testsuite/gdb.arch/aarch64-mops-watchpoint.exp
Normal file
@@ -0,0 +1,79 @@
|
||||
# Copyright 2024 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 a binary that uses MOPS (Memory Operations) instructions.
|
||||
# This test is similar to gdb.base/memops-watchpoint.exp, but specifically
|
||||
# tests MOPS instructions rather than whatever instructions are used in the
|
||||
# system libc's implementation of memset/memcpy/memmove.
|
||||
|
||||
require allow_hw_watchpoint_tests allow_aarch64_mops_tests
|
||||
|
||||
standard_testfile
|
||||
|
||||
if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \
|
||||
[list debug additional_flags=-march=armv9.3-a]] } {
|
||||
return -1
|
||||
}
|
||||
|
||||
set linespec ${srcfile}:[gdb_get_line_number "Break here"]
|
||||
if ![runto ${linespec}] {
|
||||
return -1
|
||||
}
|
||||
|
||||
gdb_test "watch -location a\[28\]" \
|
||||
"(Hardware w|W)atchpoint ${decimal}: -location a\\\[28\\\]" \
|
||||
"set watch on a"
|
||||
gdb_test "watch -location b\[28\]" \
|
||||
"(Hardware w|W)atchpoint ${decimal}: -location b\\\[28\\\]" \
|
||||
"set watchpoint on b"
|
||||
gdb_test "watch -location c\[28\]" \
|
||||
"(Hardware w|W)atchpoint ${decimal}: -location c\\\[28\\\]" \
|
||||
"set watchpoint on c"
|
||||
|
||||
gdb_test "continue" \
|
||||
[multi_line \
|
||||
"Continuing\\." \
|
||||
"" \
|
||||
"Hardware watchpoint ${decimal}: -location a\\\[28\\\]" \
|
||||
"" \
|
||||
"Old value = 104 'h'" \
|
||||
"New value = 0 '\\\\000'" \
|
||||
"$hex in main \\(\\) at .*aarch64-mops-watchpoint.c:$decimal" \
|
||||
"${decimal}\\s+__asm__ volatile \\(\"setp.*\\\\n\\\\t\""] \
|
||||
"continue until set watchpoint hits"
|
||||
|
||||
gdb_test "continue" \
|
||||
[multi_line \
|
||||
"Continuing\\." \
|
||||
"" \
|
||||
"Hardware watchpoint ${decimal}: -location b\\\[28\\\]" \
|
||||
"" \
|
||||
"Old value = 101 'e'" \
|
||||
"New value = 114 'r'" \
|
||||
"$hex in main \\(\\) at .*aarch64-mops-watchpoint.c:$decimal" \
|
||||
"${decimal}\\s+__asm__ volatile \\(\"cpyp.*\\\\n\\\\t\""] \
|
||||
"continue until cpy watchpoint hits"
|
||||
|
||||
gdb_test "continue" \
|
||||
[multi_line \
|
||||
"Continuing\\." \
|
||||
"" \
|
||||
"Hardware watchpoint ${decimal}: -location c\\\[28\\\]" \
|
||||
"" \
|
||||
"Old value = 100 'd'" \
|
||||
"New value = 114 'r'" \
|
||||
"$hex in main \\(\\) at .*aarch64-mops-watchpoint.c:$decimal" \
|
||||
"${decimal}\\s+__asm__ volatile \\(\"cpyfp.*\\\\n\\\\t\""] \
|
||||
"continue until cpyf watchpoint hits"
|
||||
@@ -123,10 +123,12 @@ proc make_val_cast {lang signed bits val} {
|
||||
return "$val as ${sign_prefix}$bits"
|
||||
} else {
|
||||
# C-like cast.
|
||||
if {$signed} {
|
||||
if {!$signed} {
|
||||
set sign_prefix "unsigned "
|
||||
} elseif {$lang == "opencl"} {
|
||||
set sign_prefix ""
|
||||
} else {
|
||||
set sign_prefix "un"
|
||||
set sign_prefix "signed "
|
||||
}
|
||||
if {$bits == 8} {
|
||||
set type "char"
|
||||
@@ -143,7 +145,7 @@ proc make_val_cast {lang signed bits val} {
|
||||
} else {
|
||||
error "$lang: unsupported bits"
|
||||
}
|
||||
return "(${sign_prefix}signed $type) $val"
|
||||
return "(${sign_prefix}$type) $val"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,7 +180,7 @@ proc test_shifts {} {
|
||||
"unknown" "ada" "modula-2" "pascal" "fortran"
|
||||
}
|
||||
if {[lsearch -exact $skip_langs $lang] >= 0} {
|
||||
return
|
||||
continue
|
||||
}
|
||||
|
||||
gdb_test_no_output "set language $lang"
|
||||
@@ -344,8 +346,11 @@ proc test_shifts {} {
|
||||
with_test_prefix "rsh neg lhs" {
|
||||
test_shift $lang "print -1 >> 0" " = -1"
|
||||
test_shift $lang "print -1 >> 1" " = -1"
|
||||
test_shift $lang "print -2 >> 1" " = -1"
|
||||
test_shift $lang "print -3 >> 1" " = -2"
|
||||
test_shift $lang "print -8 >> 1" " = -4"
|
||||
test_shift $lang "print [make_int64 $lang -8] >> 1" " = -4"
|
||||
test_rshift_tl $lang "print -8 >> 100" " = -1"
|
||||
}
|
||||
|
||||
# Make sure an unsigned 64-bit value with high bit set isn't
|
||||
@@ -360,6 +365,18 @@ proc test_shifts {} {
|
||||
test_rshift_tl $lang \
|
||||
"print -1 >> [make_uint64 $lang 0xffffffffffffffff]" " = -1"
|
||||
}
|
||||
|
||||
# Check if shift value isn't silently truncated to 32bit.
|
||||
with_test_prefix "lower-32bit-zero" {
|
||||
test_lshift_tl $lang \
|
||||
"print 1 << [make_uint64 $lang 0x100000000]" " = 0"
|
||||
test_rshift_tl $lang \
|
||||
"print 1 >> [make_uint64 $lang 0x100000000]" " = 0"
|
||||
test_lshift_tl $lang \
|
||||
"print -1 << [make_uint64 $lang 0x100000000]" " = 0"
|
||||
test_rshift_tl $lang \
|
||||
"print -1 >> [make_uint64 $lang 0x100000000]" " = -1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ proc py_remove_all_disassemblers {} {
|
||||
#
|
||||
# Each different disassembler tests some different feature of the
|
||||
# Python disassembler API.
|
||||
set nop "(nop|nop\t0)"
|
||||
set nop "(nop|nop\t0|[string_to_regexp nop\t{0}])"
|
||||
set unknown_error_pattern "unknown disassembler error \\(error = -1\\)"
|
||||
set addr_pattern "\r\n=> ${curr_pc_pattern} <\[^>\]+>:\\s+"
|
||||
set base_pattern "${addr_pattern}${nop}"
|
||||
|
||||
@@ -46,7 +46,7 @@ def check_building_disassemble_result():
|
||||
|
||||
|
||||
def is_nop(s):
|
||||
return s == "nop" or s == "nop\t0"
|
||||
return s == "nop" or s == "nop\t0" or s == "nop\t{0}"
|
||||
|
||||
|
||||
# Remove all currently registered disassemblers.
|
||||
|
||||
@@ -118,6 +118,11 @@ main ()
|
||||
c.a_method (0, 1);
|
||||
c.a_const_method (0, 1);
|
||||
C::a_static_method (0, 1);
|
||||
|
||||
struct Local { int g; } l;
|
||||
l.g = 5;
|
||||
typedef int IntType;
|
||||
IntType it = 6;
|
||||
#endif
|
||||
enum E e;
|
||||
|
||||
|
||||
@@ -85,6 +85,12 @@ proc test_fields {lang} {
|
||||
gdb_test "python print (gdb.parse_and_eval ('C::a_static_method').type.fields ()\[0\].type)" "int"
|
||||
gdb_test "python print (gdb.parse_and_eval ('C::a_static_method').type.fields ()\[1\].type)" "char"
|
||||
gdb_test "python print (gdb.parse_and_eval ('c')\['a_static_method'\].type.fields ()\[0\].type)" "int"
|
||||
|
||||
# Test function-local types.
|
||||
gdb_test "python print (gdb.lookup_type ('main()::Local'))" "Local"
|
||||
gdb_test "python print (gdb.lookup_type ('main()::Local').fields ()\[0\].type)" "int"
|
||||
gdb_test "python print (gdb.lookup_type ('main()::IntType'))" "IntType"
|
||||
gdb_test "python print (gdb.lookup_type ('main()::IntType').target ())" "int"
|
||||
}
|
||||
|
||||
# Test normal fields usage in structs.
|
||||
|
||||
78
gdb/testsuite/gdb.reverse/aarch64-mops.c
Normal file
78
gdb/testsuite/gdb.reverse/aarch64-mops.c
Normal file
@@ -0,0 +1,78 @@
|
||||
/* This test program is part of GDB, the GNU debugger.
|
||||
|
||||
Copyright 2024 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>
|
||||
|
||||
#define INITIAL_STRING "Initial fill value."
|
||||
#define NEW_STRING "Just a test string."
|
||||
#define BUF_SIZE sizeof(NEW_STRING)
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
char dest[BUF_SIZE] = INITIAL_STRING;
|
||||
char source[BUF_SIZE] = NEW_STRING;
|
||||
register char *p asm ("x19");
|
||||
register char *q asm ("x20");
|
||||
register long size asm ("x21");
|
||||
register long zero asm ("x22");
|
||||
|
||||
p = dest;
|
||||
size = BUF_SIZE;
|
||||
zero = 0;
|
||||
/* Before setp. */
|
||||
/* memset implemented in MOPS instructions. */
|
||||
__asm__ volatile ("setp [%0]!, %1!, %2\n\t"
|
||||
"setm [%0]!, %1!, %2\n\t"
|
||||
"sete [%0]!, %1!, %2\n\t"
|
||||
: "+&r"(p), "+&r"(size)
|
||||
: "r"(zero)
|
||||
: "memory");
|
||||
|
||||
/* After sete. */
|
||||
p = dest;
|
||||
q = source;
|
||||
size = BUF_SIZE;
|
||||
memcpy (dest, INITIAL_STRING, sizeof (dest));
|
||||
/* Before cpyp. */
|
||||
/* memmove implemented in MOPS instructions. */
|
||||
__asm__ volatile ("cpyp [%0]!, [%1]!, %2!\n\t"
|
||||
"cpym [%0]!, [%1]!, %2!\n\t"
|
||||
"cpye [%0]!, [%1]!, %2!\n\t"
|
||||
: "+&r" (p), "+&r" (q), "+&r" (size)
|
||||
:
|
||||
: "memory");
|
||||
|
||||
/* After cpye. */
|
||||
p = dest;
|
||||
q = source;
|
||||
size = BUF_SIZE;
|
||||
memcpy (dest, INITIAL_STRING, sizeof (dest));
|
||||
/* Before cpyfp. */
|
||||
/* memcpy implemented in MOPS instructions. */
|
||||
__asm__ volatile ("cpyfp [%0]!, [%1]!, %2!\n\t"
|
||||
"cpyfm [%0]!, [%1]!, %2!\n\t"
|
||||
"cpyfe [%0]!, [%1]!, %2!\n\t"
|
||||
: "+&r" (p), "+&r" (q), "+&r" (size)
|
||||
:
|
||||
: "memory");
|
||||
|
||||
/* After cpyfe. */
|
||||
p = dest;
|
||||
|
||||
return 0;
|
||||
}
|
||||
186
gdb/testsuite/gdb.reverse/aarch64-mops.exp
Normal file
186
gdb/testsuite/gdb.reverse/aarch64-mops.exp
Normal file
@@ -0,0 +1,186 @@
|
||||
# Copyright 2024 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 instruction record for AArch64 FEAT_MOPS instructions.
|
||||
# Based on gdb.reverse/ppc_record_test_isa_3_1.exp
|
||||
#
|
||||
# The basic flow of the record tests are:
|
||||
# 1) Stop before executing the instructions of interest. Record
|
||||
# the initial value of the registers that the instruction will
|
||||
# change, i.e. the destination register.
|
||||
# 2) Execute the instructions. Record the new value of the
|
||||
# registers that changed.
|
||||
# 3) Reverse the direction of the execution and execute back to
|
||||
# just before the instructions of interest. Record the final
|
||||
# value of the registers of interest.
|
||||
# 4) Check that the initial and new values of the registers are
|
||||
# different, i.e. the instruction changed the registers as expected.
|
||||
# 5) Check that the initial and final values of the registers are
|
||||
# the same, i.e. GDB record restored the registers to their
|
||||
# original values.
|
||||
|
||||
require allow_aarch64_mops_tests
|
||||
|
||||
standard_testfile
|
||||
|
||||
if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \
|
||||
[list debug additional_flags=-march=armv9.3-a]] } {
|
||||
return -1
|
||||
}
|
||||
|
||||
if ![runto_main] {
|
||||
return -1
|
||||
}
|
||||
|
||||
gdb_test_no_output "record full"
|
||||
|
||||
foreach_with_prefix insn_prefix {"set" "cpy" "cpyf"} {
|
||||
global decimal hex
|
||||
|
||||
set before_seq [gdb_get_line_number "Before ${insn_prefix}p"]
|
||||
set after_seq [gdb_get_line_number "After ${insn_prefix}e"]
|
||||
|
||||
gdb_test "break $before_seq" \
|
||||
"Breakpoint $decimal at $hex: file .*/aarch64-mops.c, line $decimal\\." \
|
||||
"break before instruction sequence"
|
||||
gdb_continue_to_breakpoint "about to execute instruction sequence" \
|
||||
[multi_line ".*/aarch64-mops.c:$decimal" \
|
||||
"$decimal\[ \t\]+__asm__ volatile \\(\"${insn_prefix}p \[^\r\n\]+\""]
|
||||
|
||||
# Depending on the compiler, the line number information may put GDB a few
|
||||
# instructions before the beginning of the asm statement.
|
||||
arrive_at_instruction "${insn_prefix}p"
|
||||
# Add a breakpoint that we're sure is at the prologue instruction.
|
||||
gdb_test "break *\$pc" \
|
||||
"Breakpoint $decimal at $hex: file .*/aarch64-mops.c, line $decimal\\." \
|
||||
"break at prologue instruction"
|
||||
|
||||
# Record the initial memory and register values.
|
||||
set dest_initial [get_valueof "/x" "dest" "unable to read initial" \
|
||||
"get dest initial value"]
|
||||
set x19_initial [capture_command_output "info register x19" ""]
|
||||
set x21_initial [capture_command_output "info register x21" ""]
|
||||
|
||||
# The set instructions use the ZERO variable, but not Q nor SOURCE,
|
||||
# and the other instructions are the opposite.
|
||||
if {[string compare $insn_prefix "set"] == 0} {
|
||||
set x22_initial [capture_command_output "info register x22" ""]
|
||||
} else {
|
||||
set x20_initial [capture_command_output "info register x20" ""]
|
||||
set source_initial [get_valueof "/x" "source" "unable to read initial" \
|
||||
"get source initial value"]
|
||||
}
|
||||
|
||||
gdb_test "break $after_seq" \
|
||||
"Breakpoint $decimal at $hex: file .*/aarch64-mops.c, line $decimal\\." \
|
||||
"break after instruction sequence"
|
||||
gdb_continue_to_breakpoint "executed instruction sequence" \
|
||||
[multi_line ".*/aarch64-mops.c:$decimal" "$decimal\[ \t\]+p = dest;"]
|
||||
|
||||
# Record the new memory and register values.
|
||||
set dest_new [get_valueof "/x" "dest" "unable to read new" \
|
||||
"get dest new value"]
|
||||
set x19_new [capture_command_output "info register x19" ""]
|
||||
set x21_new [capture_command_output "info register x21" ""]
|
||||
|
||||
if {[string compare $insn_prefix "set"] == 0} {
|
||||
set x22_new [capture_command_output "info register x22" ""]
|
||||
} else {
|
||||
set x20_new [capture_command_output "info register x20" ""]
|
||||
set source_new [get_valueof "/x" "source" "unable to read new" \
|
||||
"get source new value"]
|
||||
}
|
||||
|
||||
# Execute in reverse to before the instruction sequence.
|
||||
gdb_test_no_output "set exec-direction reverse"
|
||||
|
||||
gdb_continue_to_breakpoint "reversed execution of instruction sequence" \
|
||||
[multi_line ".*/aarch64-mops.c:$decimal" \
|
||||
"$decimal\[ \t\]+__asm__ volatile \\(\"${insn_prefix}p \[^\r\n\]+\""]
|
||||
|
||||
# Record the final memory and register values.
|
||||
set dest_final [get_valueof "/x" "dest" "unable to read final" \
|
||||
"get dest final value"]
|
||||
set x19_final [capture_command_output "info register x19" ""]
|
||||
set x21_final [capture_command_output "info register x21" ""]
|
||||
|
||||
if {[string compare $insn_prefix "set"] == 0} {
|
||||
set x22_final [capture_command_output "info register x22" ""]
|
||||
} else {
|
||||
set x20_final [capture_command_output "info register x20" ""]
|
||||
set source_final [get_valueof "/x" "source" "unable to read final" \
|
||||
"get source final value"]
|
||||
}
|
||||
|
||||
# Check initial and new values of dest are different.
|
||||
gdb_assert [string compare $dest_initial $dest_new] \
|
||||
"check dest initial value versus dest new value"
|
||||
|
||||
# Check initial and new values of x19 are different.
|
||||
gdb_assert [string compare $x19_initial $x19_new] \
|
||||
"check x19 initial value versus x19 new value"
|
||||
|
||||
# Check initial and new values of x21 are different.
|
||||
gdb_assert [string compare $x21_initial $x21_new] \
|
||||
"check x21 initial value versus x21 new value"
|
||||
|
||||
if {[string compare $insn_prefix "set"] == 0} {
|
||||
# Check initial and new values of x22 are the same.
|
||||
# The register with the value to set shouldn't change.
|
||||
gdb_assert ![string compare $x22_initial $x22_new] \
|
||||
"check x22 initial value versus x22 new value"
|
||||
} else {
|
||||
# Check initial and new values of x20 are different.
|
||||
gdb_assert [string compare $x20_initial $x20_new] \
|
||||
"check x20 initial value versus x20 new value"
|
||||
# Check initial and new values of source are the same.
|
||||
gdb_assert ![string compare $source_initial $source_new] \
|
||||
"check source initial value versus source new value"
|
||||
}
|
||||
|
||||
# Check initial and final values of dest are the same.
|
||||
gdb_assert ![string compare $dest_initial $dest_final] \
|
||||
"check dest initial value versus dest final value"
|
||||
|
||||
# Check initial and final values of x19 are the same.
|
||||
gdb_assert ![string compare $x19_initial $x19_final] \
|
||||
"check x19 initial value versus x19 final value"
|
||||
|
||||
# Check initial and final values of x21 are the same.
|
||||
gdb_assert ![string compare $x21_initial $x21_final] \
|
||||
"check x21 initial value versus x21 final value"
|
||||
|
||||
if {[string compare $insn_prefix "set"] == 0} {
|
||||
# Check initial and final values of x22 are the same.
|
||||
gdb_assert ![string compare $x22_initial $x22_final] \
|
||||
"check x22 initial value versus x22 final value"
|
||||
} else {
|
||||
# Check initial and final values of x20 are the same.
|
||||
gdb_assert ![string compare $x20_initial $x20_final] \
|
||||
"check x20 initial value versus x20 final value"
|
||||
|
||||
# Check initial and final values of source are the same.
|
||||
gdb_assert ![string compare $source_initial $source_final] \
|
||||
"check source initial value versus source final value"
|
||||
}
|
||||
|
||||
# Restore forward execution and go to end of recording.
|
||||
gdb_test_no_output "set exec-direction forward"
|
||||
gdb_test "record goto end" \
|
||||
[multi_line \
|
||||
"Go forward to insn number $decimal" \
|
||||
"#0 main \\(\\) at .*/aarch64-mops.c:$decimal" \
|
||||
"$decimal\[ \t\]+p = dest;"]
|
||||
}
|
||||
@@ -848,6 +848,44 @@ proc gdb_continue_to_breakpoint {name {location_pattern .*}} {
|
||||
}]
|
||||
}
|
||||
|
||||
# Check whether GDB is stopped at the given instruction.
|
||||
# INSTRUCTION should be just its mnemonic, without any arguments.
|
||||
|
||||
proc is_at_instruction { instruction } {
|
||||
global gdb_prompt hex
|
||||
|
||||
set test "pc points to $instruction"
|
||||
gdb_test_multiple {x/i $pc} $test {
|
||||
-re -wrap "=> $hex \[^\r\n\]+:\t$instruction\t\[^\r\n\]+" {
|
||||
return 1
|
||||
}
|
||||
-re "\r\n$gdb_prompt $" {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Single-steps GDB until it arrives at the given instruction.
|
||||
# INSTRUCTION should be just its mnemonic, without any arguments.
|
||||
|
||||
proc arrive_at_instruction { instruction } {
|
||||
set count 0
|
||||
|
||||
while { [is_at_instruction $instruction] != 1 } {
|
||||
gdb_test -nopass "stepi" "\[^\r\n\]+" \
|
||||
"stepi #$count to reach $instruction"
|
||||
incr count
|
||||
|
||||
if { $count > 50 } {
|
||||
fail "didn't reach $instruction"
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# gdb_internal_error_resync:
|
||||
#
|
||||
@@ -4496,6 +4534,67 @@ proc aarch64_supports_sme_svl { length } {
|
||||
return 1
|
||||
}
|
||||
|
||||
# Run a test on the target to see if it supports AArch64 MOPS (Memory
|
||||
# Operations) extensions. Return 1 if so, 0 if it does not. Note this
|
||||
# causes a restart of GDB.
|
||||
|
||||
gdb_caching_proc allow_aarch64_mops_tests {} {
|
||||
global srcdir subdir gdb_prompt inferior_exited_re
|
||||
|
||||
set me "allow_aarch64_mops_tests"
|
||||
|
||||
if { ![is_aarch64_target]} {
|
||||
return 0
|
||||
}
|
||||
|
||||
# ARMv9.3-A contains the MOPS extension. The test program doesn't use it,
|
||||
# but take the opportunity to check whether the toolchain knows about MOPS.
|
||||
set compile_flags "{additional_flags=-march=armv9.3-a}"
|
||||
|
||||
# Compile a program that tests the MOPS feature.
|
||||
set src {
|
||||
#include <stdbool.h>
|
||||
#include <sys/auxv.h>
|
||||
|
||||
#ifndef HWCAP2_MOPS
|
||||
#define HWCAP2_MOPS (1UL << 43)
|
||||
#endif
|
||||
|
||||
int main() {
|
||||
bool mops_supported = getauxval (AT_HWCAP2) & HWCAP2_MOPS;
|
||||
|
||||
return !mops_supported;
|
||||
}
|
||||
}
|
||||
|
||||
if {![gdb_simple_compile $me $src executable $compile_flags]} {
|
||||
return 0
|
||||
}
|
||||
|
||||
# Compilation succeeded so now run it via gdb.
|
||||
clean_restart $obj
|
||||
gdb_run_cmd
|
||||
gdb_expect {
|
||||
-re ".*$inferior_exited_re with code 01.*${gdb_prompt} $" {
|
||||
verbose -log "\n$me mops support not detected"
|
||||
set allow_mops_tests 0
|
||||
}
|
||||
-re ".*$inferior_exited_re normally.*${gdb_prompt} $" {
|
||||
verbose -log "\n$me: mops support detected"
|
||||
set allow_mops_tests 1
|
||||
}
|
||||
default {
|
||||
warning "\n$me: default case taken"
|
||||
set allow_mops_tests 0
|
||||
}
|
||||
}
|
||||
gdb_exit
|
||||
remote_file build delete $obj
|
||||
|
||||
verbose "$me: returning $allow_mops_tests" 2
|
||||
return $allow_mops_tests
|
||||
}
|
||||
|
||||
# A helper that compiles a test case to see if __int128 is supported.
|
||||
proc gdb_int128_helper {lang} {
|
||||
return [gdb_can_simple_compile "i128-for-$lang" {
|
||||
|
||||
@@ -1086,7 +1086,7 @@ type_length_bits (type *type)
|
||||
static bool
|
||||
check_valid_shift_count (enum exp_opcode op, type *result_type,
|
||||
type *shift_count_type, const gdb_mpz &shift_count,
|
||||
unsigned long &nbits)
|
||||
ULONGEST &nbits)
|
||||
{
|
||||
if (!shift_count_type->is_unsigned ())
|
||||
{
|
||||
@@ -1112,7 +1112,7 @@ check_valid_shift_count (enum exp_opcode op, type *result_type,
|
||||
}
|
||||
}
|
||||
|
||||
nbits = shift_count.as_integer<unsigned long> ();
|
||||
nbits = shift_count.as_integer<ULONGEST> ();
|
||||
if (nbits >= type_length_bits (result_type))
|
||||
{
|
||||
/* In Go, shifting by large amounts is defined. Be silent and
|
||||
@@ -1291,7 +1291,7 @@ scalar_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
|
||||
|
||||
case BINOP_LSH:
|
||||
{
|
||||
unsigned long nbits;
|
||||
ULONGEST nbits;
|
||||
if (!check_valid_shift_count (op, result_type, type2, v2, nbits))
|
||||
v = 0;
|
||||
else
|
||||
@@ -1301,9 +1301,23 @@ scalar_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
|
||||
|
||||
case BINOP_RSH:
|
||||
{
|
||||
unsigned long nbits;
|
||||
ULONGEST nbits;
|
||||
if (!check_valid_shift_count (op, result_type, type2, v2, nbits))
|
||||
v = 0;
|
||||
{
|
||||
/* Pretend the too-large shift was decomposed in a
|
||||
number of smaller shifts. An arithmetic signed
|
||||
right shift of a negative number always yields -1
|
||||
with such semantics. This is the right thing to
|
||||
do for Go, and we might as well do it for
|
||||
languages where it is undefined. Also, pretend a
|
||||
shift by a negative number was a shift by the
|
||||
negative number cast to unsigned, which is the
|
||||
same as shifting by a too-large number. */
|
||||
if (v1 < 0 && !result_type->is_unsigned ())
|
||||
v = -1;
|
||||
else
|
||||
v = 0;
|
||||
}
|
||||
else
|
||||
v = v1 >> nbits;
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
15.0.50.DATE-git
|
||||
15.1
|
||||
|
||||
Reference in New Issue
Block a user