current address, or for ADDRESS if specified. The output identifies
inlined frames which start at the specified address.
+maintenance info blocks [ADDRESS]
+ New command which displays information about all of the blocks at
+ ADDRESS, or at the current address if ADDRESS is not given. Blocks
+ are listed starting at the inner global block out to the most inner
+ block.
+
*** Changes in GDB 15
* The MPX commands "show/set mpx bound" have been deprecated, as Intel
#include "addrmap.h"
#include "gdbtypes.h"
#include "objfiles.h"
+#include "cli/cli-cmds.h"
+#include "inferior.h"
/* This is used by struct block to store namespace-related info for
C++ files, namely using declarations and the current namespace in
return blr;
}
+/* Implement 'maint info blocks' command. If passed an argument then
+ print a list of all blocks at the given address. With no arguments
+ then list all blocks at the current address of the current inferior. */
+
+static void
+maintenance_info_blocks (const char *arg, int from_tty)
+{
+ CORE_ADDR address;
+
+ /* With no argument use the program counter of the current thread. If
+ there is an argument then use this as the address to examine. */
+ if (arg == nullptr)
+ {
+ if (inferior_ptid == null_ptid)
+ error (_("no inferior thread"));
+
+ struct regcache *regcache = get_thread_regcache (inferior_thread ());
+ address = regcache_read_pc (regcache);
+ }
+ else
+ address = parse_and_eval_address (arg);
+
+ /* Find the inner most block for ADDRESS. */
+ const struct block *cur_block = block_for_pc (address);
+ if (cur_block == nullptr)
+ {
+ gdb_printf (_("No blocks at %s\n"), core_addr_to_string_nz (address));
+ return;
+ }
+
+ gdb_printf (_("Blocks at %s:\n"), core_addr_to_string_nz (address));
+
+ const struct objfile *toplevel_objfile = cur_block->objfile ();
+ if (toplevel_objfile != nullptr)
+ gdb_printf (_(" from objfile: [(objfile *) %s] %s\n"),
+ host_address_to_string (toplevel_objfile),
+ objfile_name (toplevel_objfile));
+
+ gdb_printf ("\n");
+
+ /* List the blocks backwards; global block (widest scope) first, down to
+ the smallest scoped block last. To do this we need to build the list
+ of blocks starting from the inner block, then print that list
+ backwards. */
+ std::vector<const struct block *> blocks;
+ while (cur_block != nullptr)
+ {
+ blocks.emplace_back (cur_block);
+ cur_block = cur_block->superblock ();
+ }
+
+ for (auto it = blocks.rbegin (); it != blocks.rend (); ++it)
+ {
+ cur_block = *it;
+
+ gdb_assert (cur_block->objfile () == toplevel_objfile);
+
+ gdb_printf (_("[(block *) %s] %s..%s\n"),
+ host_address_to_string (cur_block),
+ core_addr_to_string_nz (cur_block->start ()),
+ core_addr_to_string_nz (cur_block->end ()));
+ gdb_printf (_(" entry pc: %s\n"),
+ core_addr_to_string_nz (cur_block->entry_pc ()));
+
+ if (cur_block->is_static_block ())
+ gdb_printf (_(" is static block\n"));
+
+ if (cur_block->is_global_block ())
+ gdb_printf (_(" is global block\n"));
+
+ if (cur_block->function () != nullptr)
+ {
+ if (cur_block->inlined_p ())
+ gdb_printf (_(" inline function: %s\n"),
+ cur_block->function ()->print_name ());
+ else
+ gdb_printf (_(" function: %s\n"),
+ cur_block->function ()->print_name ());
+ }
+
+ if (cur_block->scope () != nullptr
+ && *cur_block->scope () != '\0')
+ gdb_printf (_(" scope: %s\n"), cur_block->scope ());
+
+ if (int symbol_count = mdict_size (cur_block->multidict ());
+ symbol_count > 0)
+ gdb_printf (_(" symbol count: %d\n"), symbol_count);
+
+ if (cur_block->is_contiguous ())
+ gdb_printf (_(" is contiguous\n"));
+ else
+ {
+ gdb_printf (_(" address ranges:\n"));
+ for (const blockrange &rng : cur_block->ranges ())
+ gdb_printf (_(" %s..%s\n"),
+ core_addr_to_string_nz (rng.start ()),
+ core_addr_to_string_nz (rng.end ()));
+ }
+ }
+}
+
+\f
+
+void _initialize_block ();
+void
+_initialize_block ()
+{
+ add_cmd ("blocks", class_maintenance, maintenance_info_blocks,
+ _("\
+Display block information for current thread.\n\
+\n\
+Usage:\n\
+\n\
+ maintenance info blocks [ADDRESS]\n\
+\n\
+With no ADDRESS show all blocks at the current address, starting with the\n\
+global block and working down to the inner most block.\n\
+\n\
+When ADDRESS is given, list the blocks at ADDRESS."),
+ &maintenanceinfolist);
+}
Show whether messages will be printed when a @value{GDBN} command
entered from the keyboard causes symbol information to be loaded.
+@anchor{maint print symbols}
@kindex maint print symbols
@cindex symbol dump
@kindex maint print psymbols
@end group
@end smallexample
+@kindex maint info blocks
+@item maint info blocks
+@itemx maint info blocks @var{address}
+Print information about all blocks at @var{address}, or at the current
+@code{$pc} if @var{address} is not given.
+
+For information about what blocks are in @value{GDBN} see @ref{Blocks
+In Python}.
+
+Blocks are listed starting from the global block, then the static
+block, and then proceeding through progressively narrower scopes.
+
+Here is an example of the command's output:
+@smallexample
+@group
+(@value{GDBP}) maintenance info blocks
+Blocks at 0x401137:
+ from objfile: [(objfile *) 0x50507d0] /tmp/inline_func_demo
+
+[(block *) 0x504da90] 0x401106..0x40119a
+ entry pc: 0x401106
+ is global block
+ symbol count: 2
+ is contiguous
+@end group
+@group
+[(block *) 0x504d9f0] 0x401106..0x40119a
+ entry pc: 0x401106
+ is static block
+ symbol count: 1
+ is contiguous
+@end group
+@group
+[(block *) 0x504d9a0] 0x401106..0x40119a
+ entry pc: 0x401106
+ function: main
+ is contiguous
+@end group
+@group
+[(block *) 0x504d900] 0x401137..0x401166
+ entry pc: 0x401137
+ inline function: foo
+ symbol count: 1
+ is contiguous
+@end group
+@group
+[(block *) 0x504d860] 0x401137..0x401165
+ entry pc: 0x401137
+ inline function: bar
+ symbol count: 1
+ is contiguous
+@end group
+@end smallexample
+
+The command @kbd{maint info blocks} lists the symbol count for each
+block but doesn't print the symbols themselves. The symbol names can
+be found using @kbd{maint print symbols} (@pxref{maint print
+symbols}).
+
@kindex maint print registers
@kindex maint print raw-registers
@kindex maint print cooked-registers
# 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 'maint info inline-frames' command.
+# Check the 'maint info inline-frames' and 'maint info blocks'
+# commands.
standard_testfile
return 0
}
+# Make a pattern to match 'maint info blocks' output. ARGS is the
+# list of function names we expect to see. If the function name
+# starts with 'inline_func' then we expect to see an inline block,
+# otherwise blocks are not expected to be inline.
+proc make_blocks_result { args } {
+ set result \
+ [list \
+ "Blocks at $::hex:" \
+ " from objfile: \\\[\\(objfile \\*\\) $::hex\\\] [string_to_regexp $::binfile]" \
+ ""\
+ "\\\[\\(block \\*\\) $::hex\\\] $::hex\\.\\.$::hex" \
+ " entry pc: $::hex" \
+ " is global block" \
+ ".*" \
+ "\\\[\\(block \\*\\) $::hex\\\] $::hex\\.\\.$::hex" \
+ " entry pc: $::hex" \
+ " is static block" \
+ ".*" ]
+
+ foreach func $args {
+ lappend result \
+ "\\\[\\(block \\*\\) $::hex\\\] $::hex\\.\\.$::hex" \
+ " entry pc: $::hex"
+
+ if { [string range $func 0 10] eq "inline_func" } {
+ lappend result" inline function: $func"
+ } else {
+ lappend result" function: $func"
+ }
+
+ lappend result ".*"
+ }
+
+ return [multi_line {*}$result]
+}
+
+gdb_test "maint info blocks" [make_blocks_result normal_func] \
+ "maint info blocks in normal_func only"
+
# Next forward until we find the call to inline_func_a(). The hope is
# that when we see the 'inline_func_a()' line this will be the start of
# the inlined function. This might not be the case on all
}
}
+gdb_test "maint info blocks" [make_blocks_result normal_func \
+ inline_func_a inline_func_b] \
+ "maint info blocks when all blocks visible"
+
# View the inline frame information. This should display that we are
# at the start of inline_func_a() within normal_func().
gdb_test "maint info inline-frames" \
" normal_func"] \
"check inline-frames state when just entered inline_func_b"
+gdb_test "maint info blocks" [make_blocks_result normal_func \
+ inline_func_a inline_func_b] \
+ "maint info blocks when all blocks still visible"
+
gdb_test "step" ".*" \
"step into the body of inline_func_b"
"> inline_func_b"] \
"check inline-frames state when within inline_func_b"
+gdb_test "maint info blocks" [make_blocks_result normal_func \
+ inline_func_a inline_func_b] \
+ "maint info blocks within inline function, all blocks still visible"
+
# Use the recorded $pc value to check inline frames.
gdb_test "maint info inline-frames $pc" \
[multi_line \
"> normal_func"] \
"check inline-frames state at recorded \$pc"
+gdb_test "maint info blocks" [make_blocks_result normal_func \
+ inline_func_a inline_func_b] \
+ "maint info blocks using stored \$pc, inferior still running"
+
clean_restart $binfile
# Use the recorded $pc value to check inline frames when the inferior
"> normal_func"] \
"check inline-frames state at recorded \$pc before execution starts"
+gdb_test "maint info blocks $pc" [make_blocks_result normal_func \
+ inline_func_a inline_func_b] \
+ "maint info blocks using stored \$pc, inferior not running"
+
# Trying to read the $pc from the current thread should fail if the
# inferior is not yet running.
gdb_test "maint info inline-frames" \
"^no inferior thread" \
"check inline-frames state of current thread before execution starts"
+
+gdb_test "maint info blocks" "^no inferior thread" \
+ "maint info blocks with no \$pc and inferior not running"