forked from Imagelibrary/binutils-gdb
Compare commits
66 Commits
users/abur
...
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/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
# Controls whether to enable development-mode features by default.
|
# Controls whether to enable development-mode features by default.
|
||||||
development=true
|
development=false
|
||||||
|
|
||||||
# Indicate whether this is a release branch.
|
# Indicate whether this is a release branch.
|
||||||
experimental=true
|
experimental=true
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
In releases, the date is not included in either version strings or
|
In releases, the date is not included in either version strings or
|
||||||
sonames. */
|
sonames. */
|
||||||
#define BFD_VERSION_DATE 20240526
|
#define BFD_VERSION_DATE 20240707
|
||||||
#define BFD_VERSION @bfd_version@
|
#define BFD_VERSION @bfd_version@
|
||||||
#define BFD_VERSION_STRING @bfd_version_package@ @bfd_version_string@
|
#define BFD_VERSION_STRING @bfd_version_package@ @bfd_version_string@
|
||||||
#define REPORT_BUGS_TO @report_bugs_to@
|
#define REPORT_BUGS_TO @report_bugs_to@
|
||||||
|
|||||||
2
gdb/NEWS
2
gdb/NEWS
@@ -1,7 +1,7 @@
|
|||||||
What has changed in GDB?
|
What has changed in GDB?
|
||||||
(Organized release by release)
|
(Organized release by release)
|
||||||
|
|
||||||
*** Changes since GDB 14
|
*** Changes in GDB 15
|
||||||
|
|
||||||
* The MPX commands "show/set mpx bound" have been deprecated, as Intel
|
* The MPX commands "show/set mpx bound" have been deprecated, as Intel
|
||||||
listed MPX as removed in 2019.
|
listed MPX as removed in 2019.
|
||||||
|
|||||||
@@ -78,12 +78,6 @@ public:
|
|||||||
|
|
||||||
int can_do_single_step () override;
|
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. */
|
/* These three defer to common nat/ code. */
|
||||||
void low_new_thread (struct lwp_info *lp) override
|
void low_new_thread (struct lwp_info *lp) override
|
||||||
{ aarch64_linux_new_thread (lp); }
|
{ aarch64_linux_new_thread (lp); }
|
||||||
@@ -93,6 +87,7 @@ public:
|
|||||||
{ aarch64_linux_prepare_to_resume (lp); }
|
{ aarch64_linux_prepare_to_resume (lp); }
|
||||||
|
|
||||||
void low_new_fork (struct lwp_info *parent, pid_t child_pid) override;
|
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;
|
void low_forget_process (pid_t pid) override;
|
||||||
|
|
||||||
/* Add our siginfo layout converter. */
|
/* 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
|
void
|
||||||
aarch64_linux_nat_target::post_startup_inferior (ptid_t ptid)
|
aarch64_linux_nat_target::low_init_process (pid_t pid)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
low_forget_process (pid);
|
low_forget_process (pid);
|
||||||
/* Set the hardware debug register capacity. If
|
/* Set the hardware debug register capacity. This requires the process to be
|
||||||
aarch64_linux_get_debug_reg_capacity is not called
|
ptrace-stopped, otherwise detection will fail and software watchpoints will
|
||||||
(as it is in aarch64_linux_child_post_startup_inferior) then
|
be used instead of hardware. If we allow this to be done lazily, we
|
||||||
software watchpoints will be used instead of hardware
|
cannot guarantee that it's called when the process is ptrace-stopped, so
|
||||||
watchpoints when attaching to a target. */
|
do it now. */
|
||||||
aarch64_linux_get_debug_reg_capacity (pid);
|
aarch64_linux_get_debug_reg_capacity (pid);
|
||||||
linux_nat_target::post_attach (pid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Implement the "read_description" target_ops method. */
|
/* 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)
|
if (aarch64_decode_insn (insn, &inst, 1, NULL) != 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* Look for a Load Exclusive instruction which begins the sequence. */
|
/* Look for a Load Exclusive instruction which begins the sequence,
|
||||||
if (inst.opcode->iclass == ldstexcl && bit (insn, 22))
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5186,6 +5188,71 @@ aarch64_record_asimd_load_store (aarch64_insn_decode_record *aarch64_insn_r)
|
|||||||
return AARCH64_RECORD_SUCCESS;
|
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. */
|
/* Record handler for load and store instructions. */
|
||||||
|
|
||||||
static unsigned int
|
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)
|
if (insn_bits10_11 == 0x01 || insn_bits10_11 == 0x03)
|
||||||
record_buf[aarch64_insn_r->reg_rec_count++] = reg_rn;
|
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. */
|
/* Advanced SIMD load/store instructions. */
|
||||||
else
|
else
|
||||||
return aarch64_record_asimd_load_store (aarch64_insn_r);
|
return aarch64_record_asimd_load_store (aarch64_insn_r);
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
%{
|
%{
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <unordered_map>
|
||||||
#include "expression.h"
|
#include "expression.h"
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
#include "parser-defs.h"
|
#include "parser-defs.h"
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ public:
|
|||||||
|
|
||||||
/* Handle process creation and exit. */
|
/* Handle process creation and exit. */
|
||||||
void low_new_fork (struct lwp_info *parent, pid_t child_pid) override;
|
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;
|
void low_forget_process (pid_t pid) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -805,6 +806,19 @@ arm_linux_process_info_get (pid_t pid)
|
|||||||
return proc;
|
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
|
/* Called whenever GDB is no longer debugging process PID. It deletes
|
||||||
data structures that keep track of debug register state. */
|
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 ();
|
struct type *scope_type = scope_sym.symbol->type ();
|
||||||
|
|
||||||
/* If the scope is a function/method, then look up NESTED as a local
|
/* 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
|
if ((scope_type->code () == TYPE_CODE_FUNC
|
||||||
|| scope_type->code () == TYPE_CODE_METHOD)
|
|| 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 (),
|
return lookup_symbol (nested, scope_sym.symbol->value_block (),
|
||||||
domain, NULL);
|
domain, NULL);
|
||||||
|
|
||||||
|
|||||||
@@ -658,17 +658,30 @@ annotate/index.html: $(ANNOTATE_DOC_FILES)
|
|||||||
-I $(srcdir) \
|
-I $(srcdir) \
|
||||||
$(srcdir)/annotate.texinfo
|
$(srcdir)/annotate.texinfo
|
||||||
|
|
||||||
# Man pages
|
# Man pages. The TEXI2POD and TEXI2MAN steps are performed within a
|
||||||
%.pod : gdb.texinfo $(GDB_DOC_FILES)
|
# single recipe to support how we distribute GDB releases. A release
|
||||||
$(ECHO_TEXI2POD) $(TEXI2POD) $(MANCONF) -D$* < $(srcdir)/gdb.texinfo > $@
|
# includes the .1 and .5 man pages in the source tree, but not the
|
||||||
|
# .pod files.
|
||||||
$(MAN1S) : %.1 : %.pod $(GDB_DOC_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$$$$ && \
|
$(ECHO_TEXI2MAN) ($(POD2MAN1) $*.pod | sed -e '/^.if n .na/d' > $@.T$$$$ && \
|
||||||
mv -f $@.T$$$$ $@) || (rm -f $@.T$$$$ && exit 1)
|
mv -f $@.T$$$$ $@) || (rm -f $@.T$$$$ && exit 1)
|
||||||
|
$(SILENCE) rm -f $*.pod
|
||||||
|
|
||||||
$(MAN5S) : %.5 : %.pod $(GDB_DOC_FILES)
|
$(MAN5S) : %.5 : $(GDB_DOC_FILES)
|
||||||
$(ECHO_TEXI2MAN) ($(POD2MAN1) $*.pod | sed -e '/^.if n .na/d' > $@.T$$$$ && \
|
$(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)
|
mv -f $@.T$$$$ $@) || (rm -f $@.T$$$$ && exit 1)
|
||||||
|
$(SILENCE) rm -f $*.pod
|
||||||
|
|
||||||
force:
|
force:
|
||||||
|
|
||||||
|
|||||||
@@ -528,7 +528,7 @@ objfile_find_memory_regions (struct target_ops *self,
|
|||||||
find_memory_region_ftype func, void *obfd)
|
find_memory_region_ftype func, void *obfd)
|
||||||
{
|
{
|
||||||
/* Use objfile data to create memory sections. */
|
/* 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. */
|
/* Call callback function for each objfile section. */
|
||||||
for (objfile *objfile : current_program_space->objfiles ())
|
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
|
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
|
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
|
iconv_open. We put the endianness into the encoding name to avoid
|
||||||
hosts that emit a BOM when the unadorned name is used. */
|
hosts that emit a BOM when the unadorned name is used.
|
||||||
#if defined (__STDC_ISO_10646__)
|
|
||||||
|
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 USE_INTERMEDIATE_ENCODING_FUNCTION
|
||||||
#define INTERMEDIATE_ENCODING intermediate_encoding ()
|
#define INTERMEDIATE_ENCODING intermediate_encoding ()
|
||||||
const char *intermediate_encoding (void);
|
const char *intermediate_encoding (void);
|
||||||
|
|||||||
@@ -280,13 +280,13 @@ struct gdb_mpz
|
|||||||
gdb_mpz operator>> (unsigned long nbits) const
|
gdb_mpz operator>> (unsigned long nbits) const
|
||||||
{
|
{
|
||||||
gdb_mpz result;
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
gdb_mpz &operator>>= (unsigned long nbits)
|
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;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -454,6 +454,12 @@ linux_init_ptrace_procfs (pid_t pid, int attached)
|
|||||||
linux_ptrace_init_warnings ();
|
linux_ptrace_init_warnings ();
|
||||||
linux_proc_init_warnings ();
|
linux_proc_init_warnings ();
|
||||||
proc_mem_file_is_writable ();
|
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 ()
|
linux_nat_target::~linux_nat_target ()
|
||||||
|
|||||||
@@ -164,6 +164,12 @@ public:
|
|||||||
virtual void low_new_clone (struct lwp_info *parent, pid_t child_lwp)
|
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
|
/* The method to call, if any, when a process is no longer
|
||||||
attached. */
|
attached. */
|
||||||
virtual void low_forget_process (pid_t pid)
|
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_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_forget_process (pid_t pid) override;
|
||||||
|
|
||||||
void low_prepare_to_resume (struct lwp_info *) 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;
|
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
|
/* Clean up the per-process info associated with PID. When using the
|
||||||
HWDEBUG interface, we also erase the per-thread state of installed
|
HWDEBUG interface, we also erase the per-thread state of installed
|
||||||
debug registers for all the threads that belong to the group of PID.
|
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;
|
disasm_info_object *obj = (disasm_info_object *) self;
|
||||||
DISASMPY_DISASM_INFO_REQUIRE_VALID (obj);
|
DISASMPY_DISASM_INFO_REQUIRE_VALID (obj);
|
||||||
|
|
||||||
LONGEST length, offset = 0;
|
gdb_py_longest length, offset = 0;
|
||||||
gdb::unique_xmalloc_ptr<gdb_byte> buffer;
|
gdb::unique_xmalloc_ptr<gdb_byte> buffer;
|
||||||
static const char *keywords[] = { "length", "offset", nullptr };
|
static const char *keywords[] = { "length", "offset", nullptr };
|
||||||
|
|
||||||
if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "L|L", keywords,
|
if (!gdb_PyArg_ParseTupleAndKeywords (args, kw,
|
||||||
&length, &offset))
|
GDB_PY_LL_ARG "|" GDB_PY_LL_ARG,
|
||||||
|
keywords, &length, &offset))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
/* The apparent address from which we are reading memory. Note that in
|
/* 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
|
/* The DisassembleInfo.read_memory method expects an offset from the
|
||||||
address stored within the DisassembleInfo object; calculate that
|
address stored within the DisassembleInfo object; calculate that
|
||||||
offset here. */
|
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
|
/* Now call the DisassembleInfo.read_memory method. This might have been
|
||||||
overridden by the user. */
|
overridden by the user. */
|
||||||
gdbpy_ref<> result_obj (PyObject_CallMethod ((PyObject *) obj,
|
gdbpy_ref<> result_obj (PyObject_CallMethod ((PyObject *) obj,
|
||||||
"read_memory",
|
"read_memory",
|
||||||
"KL", len, offset));
|
"I" GDB_PY_LL_ARG, len, offset));
|
||||||
|
|
||||||
/* Handle any exceptions. */
|
/* Handle any exceptions. */
|
||||||
if (result_obj == nullptr)
|
if (result_obj == nullptr)
|
||||||
|
|||||||
@@ -266,7 +266,7 @@ stpy_lazy_string_elt_type (lazy_string_object *lazy)
|
|||||||
{
|
{
|
||||||
case TYPE_CODE_PTR:
|
case TYPE_CODE_PTR:
|
||||||
case TYPE_CODE_ARRAY:
|
case TYPE_CODE_ARRAY:
|
||||||
return realtype->target_type ();
|
return check_typedef (realtype->target_type ());
|
||||||
default:
|
default:
|
||||||
/* This is done to preserve existing behaviour. PR 20769.
|
/* This is done to preserve existing behaviour. PR 20769.
|
||||||
E.g., gdb.parse_and_eval("my_int_variable").lazy_string().type. */
|
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"
|
return "$val as ${sign_prefix}$bits"
|
||||||
} else {
|
} else {
|
||||||
# C-like cast.
|
# C-like cast.
|
||||||
if {$signed} {
|
if {!$signed} {
|
||||||
|
set sign_prefix "unsigned "
|
||||||
|
} elseif {$lang == "opencl"} {
|
||||||
set sign_prefix ""
|
set sign_prefix ""
|
||||||
} else {
|
} else {
|
||||||
set sign_prefix "un"
|
set sign_prefix "signed "
|
||||||
}
|
}
|
||||||
if {$bits == 8} {
|
if {$bits == 8} {
|
||||||
set type "char"
|
set type "char"
|
||||||
@@ -143,7 +145,7 @@ proc make_val_cast {lang signed bits val} {
|
|||||||
} else {
|
} else {
|
||||||
error "$lang: unsupported bits"
|
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"
|
"unknown" "ada" "modula-2" "pascal" "fortran"
|
||||||
}
|
}
|
||||||
if {[lsearch -exact $skip_langs $lang] >= 0} {
|
if {[lsearch -exact $skip_langs $lang] >= 0} {
|
||||||
return
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
gdb_test_no_output "set language $lang"
|
gdb_test_no_output "set language $lang"
|
||||||
@@ -344,8 +346,11 @@ proc test_shifts {} {
|
|||||||
with_test_prefix "rsh neg lhs" {
|
with_test_prefix "rsh neg lhs" {
|
||||||
test_shift $lang "print -1 >> 0" " = -1"
|
test_shift $lang "print -1 >> 0" " = -1"
|
||||||
test_shift $lang "print -1 >> 1" " = -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 -8 >> 1" " = -4"
|
||||||
test_shift $lang "print [make_int64 $lang -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
|
# Make sure an unsigned 64-bit value with high bit set isn't
|
||||||
@@ -360,6 +365,18 @@ proc test_shifts {} {
|
|||||||
test_rshift_tl $lang \
|
test_rshift_tl $lang \
|
||||||
"print -1 >> [make_uint64 $lang 0xffffffffffffffff]" " = -1"
|
"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
|
# Each different disassembler tests some different feature of the
|
||||||
# Python disassembler API.
|
# 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 unknown_error_pattern "unknown disassembler error \\(error = -1\\)"
|
||||||
set addr_pattern "\r\n=> ${curr_pc_pattern} <\[^>\]+>:\\s+"
|
set addr_pattern "\r\n=> ${curr_pc_pattern} <\[^>\]+>:\\s+"
|
||||||
set base_pattern "${addr_pattern}${nop}"
|
set base_pattern "${addr_pattern}${nop}"
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ def check_building_disassemble_result():
|
|||||||
|
|
||||||
|
|
||||||
def is_nop(s):
|
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.
|
# Remove all currently registered disassemblers.
|
||||||
|
|||||||
@@ -118,6 +118,11 @@ main ()
|
|||||||
c.a_method (0, 1);
|
c.a_method (0, 1);
|
||||||
c.a_const_method (0, 1);
|
c.a_const_method (0, 1);
|
||||||
C::a_static_method (0, 1);
|
C::a_static_method (0, 1);
|
||||||
|
|
||||||
|
struct Local { int g; } l;
|
||||||
|
l.g = 5;
|
||||||
|
typedef int IntType;
|
||||||
|
IntType it = 6;
|
||||||
#endif
|
#endif
|
||||||
enum E e;
|
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 ()\[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 ()\[1\].type)" "char"
|
||||||
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 ()\[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.
|
# 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:
|
# gdb_internal_error_resync:
|
||||||
#
|
#
|
||||||
@@ -4496,6 +4534,67 @@ proc aarch64_supports_sme_svl { length } {
|
|||||||
return 1
|
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.
|
# A helper that compiles a test case to see if __int128 is supported.
|
||||||
proc gdb_int128_helper {lang} {
|
proc gdb_int128_helper {lang} {
|
||||||
return [gdb_can_simple_compile "i128-for-$lang" {
|
return [gdb_can_simple_compile "i128-for-$lang" {
|
||||||
|
|||||||
@@ -1086,7 +1086,7 @@ type_length_bits (type *type)
|
|||||||
static bool
|
static bool
|
||||||
check_valid_shift_count (enum exp_opcode op, type *result_type,
|
check_valid_shift_count (enum exp_opcode op, type *result_type,
|
||||||
type *shift_count_type, const gdb_mpz &shift_count,
|
type *shift_count_type, const gdb_mpz &shift_count,
|
||||||
unsigned long &nbits)
|
ULONGEST &nbits)
|
||||||
{
|
{
|
||||||
if (!shift_count_type->is_unsigned ())
|
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))
|
if (nbits >= type_length_bits (result_type))
|
||||||
{
|
{
|
||||||
/* In Go, shifting by large amounts is defined. Be silent and
|
/* 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:
|
case BINOP_LSH:
|
||||||
{
|
{
|
||||||
unsigned long nbits;
|
ULONGEST nbits;
|
||||||
if (!check_valid_shift_count (op, result_type, type2, v2, nbits))
|
if (!check_valid_shift_count (op, result_type, type2, v2, nbits))
|
||||||
v = 0;
|
v = 0;
|
||||||
else
|
else
|
||||||
@@ -1301,9 +1301,23 @@ scalar_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
|
|||||||
|
|
||||||
case BINOP_RSH:
|
case BINOP_RSH:
|
||||||
{
|
{
|
||||||
unsigned long nbits;
|
ULONGEST nbits;
|
||||||
if (!check_valid_shift_count (op, result_type, type2, v2, 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
|
else
|
||||||
v = v1 >> nbits;
|
v = v1 >> nbits;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
15.0.50.DATE-git
|
15.1
|
||||||
|
|||||||
Reference in New Issue
Block a user