return is_target_filename (bfd_get_filename (abfd));
}
-/* For `gdb_bfd_open_from_target_memory`. */
+/* For `gdb_bfd_open_from_target_memory`. An object that manages the
+ details of a BFD in target memory. */
struct target_buffer
{
- CORE_ADDR base;
- ULONGEST size;
+ /* Constructor. BASE and SIZE define where the BFD can be found in
+ target memory. */
+ target_buffer (CORE_ADDR base, ULONGEST size)
+ : m_base (base),
+ m_size (size)
+ {
+ m_filename
+ = xstrprintf ("<in-memory@%s>", core_addr_to_string_nz (m_base));
+ }
+
+ /* Return the size of the in-memory BFD file. */
+ ULONGEST size () const
+ { return m_size; }
+
+ /* Return the base address of the in-memory BFD file. */
+ CORE_ADDR base () const
+ { return m_base; }
+
+ /* Return a generated filename for the in-memory BFD file. The generated
+ name will include the M_BASE value. */
+ const char *filename () const
+ { return m_filename.get (); }
+
+private:
+ /* The base address of the in-memory BFD file. */
+ CORE_ADDR m_base;
+
+ /* The size (in-bytes) of the in-memory BFD file. */
+ ULONGEST m_size;
+
+ /* Holds the generated name of the in-memory BFD file. */
+ gdb::unique_xmalloc_ptr<char> m_filename;
};
/* For `gdb_bfd_open_from_target_memory`. Opening the file is a no-op. */
static int
mem_bfd_iovec_close (struct bfd *abfd, void *stream)
{
- xfree (stream);
+ struct target_buffer *buffer = (target_buffer *) stream;
+ delete buffer;
/* Zero means success. */
return 0;
mem_bfd_iovec_pread (struct bfd *abfd, void *stream, void *buf,
file_ptr nbytes, file_ptr offset)
{
- int err;
struct target_buffer *buffer = (struct target_buffer *) stream;
/* If this read will read all of the file, limit it to just the rest. */
- if (offset + nbytes > buffer->size)
- nbytes = buffer->size - offset;
+ if (offset + nbytes > buffer->size ())
+ nbytes = buffer->size () - offset;
/* If there are no more bytes left, we've reached EOF. */
if (nbytes == 0)
return 0;
- err = target_read_memory (buffer->base + offset, (gdb_byte *) buf, nbytes);
+ int err
+ = target_read_memory (buffer->base () + offset, (gdb_byte *) buf, nbytes);
if (err)
return -1;
struct target_buffer *buffer = (struct target_buffer*) stream;
memset (sb, 0, sizeof (struct stat));
- sb->st_size = buffer->size;
+ sb->st_size = buffer->size ();
return 0;
}
gdb_bfd_open_from_target_memory (CORE_ADDR addr, ULONGEST size,
const char *target)
{
- struct target_buffer *buffer = XNEW (struct target_buffer);
+ struct target_buffer *buffer = new target_buffer (addr, size);
- buffer->base = addr;
- buffer->size = size;
- return gdb_bfd_openr_iovec ("<in-memory>", target,
+ return gdb_bfd_openr_iovec (buffer->filename (), target,
mem_bfd_iovec_open,
buffer,
mem_bfd_iovec_pread,
--- /dev/null
+# Copyright 2022 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/>.
+
+# Check the BFD filename (as used in the symfile name) that is
+# automatically generated for in-memory BFD files, as used by the JIT
+# system within GDB.
+#
+# Additionally, check that GDB cau use 'dump binary memory' to write
+# out the in-memory JIT files.
+
+if {[skip_shlib_tests]} {
+ untested "skipping shared library tests"
+ return -1
+}
+
+load_lib jit-elf-helpers.exp
+
+# The main code that loads and registers JIT objects.
+set main_basename "jit-elf-main"
+set main_srcfile ${srcdir}/${subdir}/${main_basename}.c
+set main_binfile [standard_output_file ${main_basename}]
+
+# The shared library that gets loaded as JIT objects.
+set jit_solib_basename jit-elf-solib
+set jit_solib_srcfile ${srcdir}/${subdir}/${jit_solib_basename}.c
+
+# Compile two shared libraries to use as JIT objects.
+set jit_solibs_target [compile_and_download_n_jit_so \
+ $jit_solib_basename $jit_solib_srcfile 2 \
+ {debug}]
+if { $jit_solibs_target == -1 } {
+ return
+}
+
+# Compile the main code (which loads the JIT objects).
+if { [compile_jit_main ${main_srcfile} ${main_binfile} {}] != 0 } {
+ return
+}
+
+clean_restart $::main_binfile
+if { ![runto_main] } {
+ return
+}
+
+# Poke desired values directly into inferior instead of using "set
+# args" because "set args" does not work under gdbserver.
+set count [expr [llength $jit_solibs_target] + 1]
+gdb_test_no_output "set var argc=$count" "forging argc"
+gdb_test_no_output "set var argv=fake_argv" "forging argv"
+for {set i 1} {$i < $count} {incr i} {
+ set jit_solib_target [lindex $jit_solibs_target [expr $i-1]]
+ gdb_test_no_output "set var argv\[$i\]=\"${jit_solib_target}\"" \
+ "forging argv\[$i\]"
+}
+
+# Run until the JIT libraries are loaded.
+gdb_breakpoint [gdb_get_line_number "break here 1" $::main_srcfile]
+gdb_continue_to_breakpoint "break here 1"
+
+# Confirm that the two expected functions are available.
+gdb_test "info function ^jit_function" \
+ [multi_line \
+ "File \[^\r\n\]+jit-elf-solib.c:" \
+ "${decimal}:\\s+int jit_function_0001\\(\\);" \
+ "${decimal}:\\s+int jit_function_0002\\(\\);"]
+
+# Capture the addresses of each JIT symfile.
+set symfile_addrs {}
+set symfile_lengths {}
+gdb_test_multiple "maint info jit" "" {
+ -re "^maint info jit\r\n" {
+ exp_continue
+ }
+ -re "^jit_code_entry address\\s+symfile address\\s+symfile size\\s*\r\n" {
+ exp_continue
+ }
+ -re "^${hex}\\s+(${hex})\\s+(${decimal})\\s*\r\n" {
+ lappend symfile_addrs $expect_out(1,string)
+ lappend symfile_lengths $expect_out(2,string)
+ exp_continue
+ }
+ -re "^$gdb_prompt $" {
+ }
+}
+
+# Now check the 'maint info symtabs' output to ensure that each
+# symfile is mentioned, and that the names are as expected.
+set bfd_name_addrs {}
+gdb_test_multiple "maint info symtabs" "" {
+ -re "^maint info symtabs\r\n" {
+ exp_continue
+ }
+ -re "^\\\}\\s*\r\n" {
+ exp_continue
+ }
+ -re "^\\\{ objfile <in-memory@($hex)>\\s+\[^\r\n\]+\r\n" {
+ lappend bfd_name_addrs $expect_out(1,string)
+ exp_continue
+ }
+ -re "^\\\{ objfile (\\S+)\\s+\[^\r\n\]+\r\n" {
+ exp_continue
+ }
+ -re "^\\s+\[^\r\n\]+\r\n" {
+ exp_continue
+ }
+ -re "^$gdb_prompt $" {
+ }
+}
+
+# Now dump each JIT solib using the 'dump binary memory' command.
+set count 0
+foreach addr $symfile_addrs len $symfile_lengths {
+ incr count
+ set output [standard_output_file "dump-elf-solib.${count}.so"]
+ set end [expr $addr + $len]
+ gdb_test_no_output "dump binary memory $output $addr $end" \
+ "dump jit solib $count"
+
+ gdb_assert { [cmp_binary_files $output [standard_output_file "jit-elf-solib.${count}.so"]] == 0} \
+ "check dump of jit solib $count is as expected"
+}
+
+
+# Check that each of the expected jit symfile addresses was mentioned
+# in an in-memory BFD filename.
+set count 1
+foreach addr $symfile_addrs {
+ # Drop any loading zeros from the symfile address.
+ set addr [format 0x%x $addr]
+
+ # Check there was a BFD with the expected address in its name.
+ gdb_assert { [expr [lsearch -exact $bfd_name_addrs $addr] != -1] } \
+ "check for in-memory bfd $count"
+ incr count
+}
+
+# Continue until the JIT libraries are unloaded.
+gdb_breakpoint [gdb_get_line_number "break here 2" $::main_srcfile]
+gdb_continue_to_breakpoint "break here 2"
+
+# All jit librares must have been unregistered.
+gdb_test "info function jit_function" \
+ "All functions matching regular expression \"jit_function\":"