monitor: add 'qXfer:memory-map:read' command`

Fixes #5004
This commit is contained in:
Christian Prochaska 2023-09-20 13:41:50 +02:00 committed by Christian Helmuth
parent c6881a8126
commit d77cb2b1fc
4 changed files with 188 additions and 13 deletions

View File

@ -193,6 +193,26 @@ if {![regexp {Genode::Lock::lock} $output] ||
exit -1
}
puts "\n"
puts "----- test: memory map -----"
puts ""
send "info mem\n"
run_genode_until {\(gdb\)} 20 $gdb_id
if {![regexp {..*y.*0x0000000000004000 0x0000000000006000 rw nocache} $output] ||
![regexp {..*y.*0x0000000000008000 0x0000000000010000 rw nocache} $output] ||
![regexp {..*y.*0x0000000000010000 0x0000000000012000 rw nocache} $output] ||
![regexp {..*y.*0x0000000000030000 0x00000000000..000 rw nocache} $output] ||
![regexp {7.*y.*0x0000000001000000 0x000000000100.000 rw nocache} $output] ||
![regexp {8.*y.*0x000000000100.000 0x000000000100.000 rw nocache} $output] ||
![regexp {9.*y.*0x00000000400fb000 0x00000000400ff000 rw nocache} $output] ||
![regexp {1..*y.*0x00000000401ef000 0x00000000401ff000 rw nocache} $output] ||
![regexp {1..*y.*0x00000000402f.000 0x00000000402ff000 rw nocache} $output]} {
puts stderr "*** Error: memory map is not as expected"
exit -1
}
puts "\n"
puts "----- test: stack trace of second inferior -----"
puts ""
@ -217,4 +237,22 @@ if {![regexp {Genode::Signal_receiver::block_for_signal} $output] } {
exit -1
}
puts "\n"
puts "----- test: memory map of second inferior -----"
puts ""
send "info mem\n"
run_genode_until {\(gdb\)} 20 $gdb_id
if {![regexp {..*y.*0x0000000000008000 0x0000000000010000 rw nocache} $output] ||
![regexp {..*y.*0x0000000000010000 0x0000000000012000 rw nocache} $output] ||
![regexp {..*y.*0x0000000000030000 0x00000000000..000 ro nocache} $output] ||
![regexp {5.*y.*0x0000000001000000 0x000000000100.000 ro nocache} $output] ||
![regexp {6.*y.*0x000000000100.000 0x000000000100.000 rw nocache} $output] ||
![regexp {7.*y.*0x00000000400fb000 0x00000000400ff000 rw nocache} $output] ||
![regexp {..*y.*0x00000000401ef000 0x00000000401ff000 rw nocache} $output]} {
puts stderr "*** Error: memory map of second inferior is not as expected"
exit -1
}
puts ""

View File

@ -53,6 +53,78 @@ struct Monitor::Gdb::State : Noncopyable
}
};
struct Memory_map
{
char _buf[1024*16] { };
size_t _len = 0;
Memory_map(Inferior_pd &inferior)
{
typedef String<16> Value;
Xml_generator xml(_buf, sizeof(_buf), "memory-map", [&] {
inferior._address_space.for_each_region(
[&] (Monitored_region_map::Region const &region) {
if (region.cap == inferior._linker_area.dataspace()) {
inferior._linker_area.for_each_region(
[&] (Monitored_region_map::Region const
&linker_area_region) {
xml.node("memory", [&] {
xml.attribute("type",
linker_area_region.writeable ?
"ram" : "rom");
xml.attribute("start",
Value(Hex(region.addr +
linker_area_region.addr)));
xml.attribute("length",
Value(Hex(linker_area_region.size)));
});
});
return;
}
if (region.cap == inferior._stack_area.dataspace()) {
inferior._stack_area.for_each_region(
[&] (Monitored_region_map::Region const
&stack_area_region) {
xml.node("memory", [&] {
xml.attribute("type",
stack_area_region.writeable ?
"ram" : "rom");
xml.attribute("start",
Value(Hex(region.addr +
stack_area_region.addr)));
xml.attribute("length",
Value(Hex(stack_area_region.size)));
});
});
return;
}
xml.node("memory", [&] {
xml.attribute("type", region.writeable ? "ram" : "rom");
xml.attribute("start", Value(Hex(region.addr)));
xml.attribute("length", Value(Hex(region.size)));
});
});
});
_len = strlen(_buf);
}
void with_bytes(auto const &fn) const
{
Const_byte_range_ptr const ptr { _buf, _len };
fn(ptr);
}
};
Memory_accessor &_memory_accessor;
struct Current : Noncopyable
@ -239,6 +311,7 @@ struct qSupported : Command_with_separator
print(out, "vContSupported+;");
print(out, "qXfer:features:read+;"); /* XML target descriptions */
print(out, "qXfer:threads:read+;");
print(out, "qXfer:memory-map:read+;");
print(out, "multiprocess+;");
print(out, "QNonStop+;");
print(out, "swbreak+;");
@ -304,6 +377,15 @@ struct qXfer : Command_with_separator
handled = true;
});
with_skipped_prefix(args, "memory-map:read::", [&] (Const_byte_range_ptr const &args) {
if (state.current_defined()) {
State::Memory_map const memory_map(state._current->pd);
memory_map.with_bytes([&] (Const_byte_range_ptr const &bytes) {
_send_window(out, bytes, Window::from_args(args)); });
}
handled = true;
});
if (!handled)
warning("GDB ", name, " command unsupported: ", Cstring(args.start, args.num_bytes));
}

View File

@ -28,15 +28,6 @@ struct Monitor::Inferior_pd : Monitored_pd_session
{
Inferiors::Element _inferiors_elem;
Monitored_region_map _address_space {
_ep, _real.call<Pd_session::Rpc_address_space>(), "address space" };
Monitored_region_map _stack_area {
_ep, _real.call<Pd_session::Rpc_stack_area>(), "stack area" };
Monitored_region_map _linker_area {
_ep, _real.call<Pd_session::Rpc_linker_area>(), "linker area" };
Threads _threads { };
Threads::Id _last_thread_id { };
@ -47,6 +38,16 @@ struct Monitor::Inferior_pd : Monitored_pd_session
Allocator &_alloc; /* used for allocating 'Ram_ds' objects */
Ram_allocator &_wx_ram; /* RAM used for writeable text segments */
Monitored_region_map _address_space {
_ep, _real.call<Pd_session::Rpc_address_space>(), "address space",
_alloc };
Monitored_region_map _stack_area {
_ep, _real.call<Pd_session::Rpc_stack_area>(), "stack area", _alloc };
Monitored_region_map _linker_area {
_ep, _real.call<Pd_session::Rpc_linker_area>(), "linker area", _alloc };
struct Policy
{
bool wait; /* wait for GDB continue command */

View File

@ -27,8 +27,6 @@ namespace Monitor { struct Monitored_region_map; }
struct Monitor::Monitored_region_map : Monitored_rpc_object<Region_map>
{
using Monitored_rpc_object::Monitored_rpc_object;
/* see the comment in base/include/region_map/client.h */
Dataspace_capability _rm_ds_cap { };
@ -97,6 +95,40 @@ struct Monitor::Monitored_region_map : Monitored_rpc_object<Region_map>
_writeable_text_segments.construct(alloc, ram, local_rm);
}
struct Region : List<Region>::Element
{
Dataspace_capability cap;
addr_t addr;
size_t size;
bool writeable;
Region(Dataspace_capability cap, addr_t addr, size_t size,
bool writeable)
: cap(cap), addr(addr), size(size), writeable(writeable) { }
};
List<Region> _regions { };
void for_each_region(auto const &fn) const
{
for (Region const *region = _regions.first(); region; region = region->next())
fn(*region);
}
Allocator &_alloc;
Monitored_region_map(Entrypoint &ep, Capability<Region_map> real,
Name const &name, Allocator &alloc)
: Monitored_rpc_object(ep, real, name),
_alloc(alloc) { }
~Monitored_region_map()
{
while (Region *region = _regions.first()) {
_regions.remove(region);
destroy(_alloc, region);
}
}
/**************************
** Region_map interface **
@ -114,13 +146,35 @@ struct Monitor::Monitored_region_map : Monitored_rpc_object<Region_map>
writeable = true;
}
return _real.call<Rpc_attach>(ds, size, offset, use_local_addr, local_addr,
executable, writeable);
Local_addr attached_addr = _real.call<Rpc_attach>(ds, size, offset,
use_local_addr,
local_addr,
executable,
writeable);
size_t region_size = size ? size :
(Dataspace_client(ds).size() - offset);
enum { PAGE_SIZE_LOG2 = 12 };
region_size = align_addr(region_size, PAGE_SIZE_LOG2);
_regions.insert(new (_alloc) Region(ds, (addr_t)attached_addr,
region_size, writeable));
return attached_addr;
}
void detach(Local_addr local_addr) override
{
_real.call<Rpc_detach>(local_addr);
addr_t addr = (addr_t)local_addr;
for (Region *region = _regions.first(); region; region = region->next()) {
if ((addr >= region->addr) &&
(addr <= (region->addr + region->size - 1))) {
_regions.remove(region);
destroy(_alloc, region);
break;
}
}
}
void fault_handler(Signal_context_capability) override