8281023: NMT integration into pp debug command does not work

Reviewed-by: zgu, iklam
This commit is contained in:
Thomas Stuefe 2022-02-03 14:12:29 +00:00
parent 63a00a0df2
commit 010965c86a
5 changed files with 72 additions and 43 deletions

@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "runtime/os.hpp"
#include "runtime/safefetch.inline.hpp"
#include "services/mallocSiteTable.hpp"
#include "services/mallocTracker.hpp"
#include "services/mallocTracker.inline.hpp"
@ -289,3 +290,32 @@ void* MallocTracker::record_free(void* memblock) {
header->release();
return (void*)header;
}
// Given a pointer, if it seems to point to the start of a valid malloced block,
// print the block. Note that since there is very low risk of memory looking
// accidentally like a valid malloc block header (canaries and all) this is not
// totally failproof. Only use this during debugging or when you can afford
// signals popping up, e.g. when writing an hs_err file.
bool MallocTracker::print_pointer_information(const void* p, outputStream* st) {
assert(MemTracker::enabled(), "NMT must be enabled");
if (CanUseSafeFetch32() && os::is_readable_pointer(p)) {
const NMT_TrackingLevel tracking_level = MemTracker::tracking_level();
const MallocHeader* mhdr = (const MallocHeader*)MallocTracker::get_base(const_cast<void*>(p), tracking_level);
char msg[256];
address p_corrupted;
if (os::is_readable_pointer(mhdr) &&
mhdr->check_block_integrity(msg, sizeof(msg), &p_corrupted)) {
st->print_cr(PTR_FORMAT " malloc'd " SIZE_FORMAT " bytes by %s",
p2i(p), mhdr->size(), NMTUtil::flag_to_name(mhdr->flags()));
if (tracking_level == NMT_detail) {
NativeCallStack ncs;
if (mhdr->get_stack(ncs)) {
ncs.print_on(st);
st->cr();
}
}
return true;
}
}
return false;
}

@ -31,6 +31,8 @@
#include "services/nmtCommon.hpp"
#include "utilities/nativeCallStack.hpp"
class outputStream;
/*
* This counter class counts memory allocation and deallocation,
* records total memory allocation size and number of allocations.
@ -438,6 +440,14 @@ class MallocTracker : AllStatic {
static inline void record_arena_size_change(ssize_t size, MEMFLAGS flags) {
MallocMemorySummary::record_arena_size_change(size, flags);
}
// Given a pointer, if it seems to point to the start of a valid malloced block,
// print the block. Note that since there is very low risk of memory looking
// accidentally like a valid malloc block header (canaries and all) this is not
// totally failproof. Only use this during debugging or when you can afford
// signals popping up, e.g. when writing an hs_err file.
static bool print_pointer_information(const void* p, outputStream* st);
private:
static inline MallocHeader* malloc_header(void *memblock) {
assert(memblock != NULL, "NULL pointer");

@ -672,28 +672,32 @@ bool VirtualMemoryTracker::walk_virtual_memory(VirtualMemoryWalker* walker) {
return true;
}
class FindAndSnapshotRegionWalker : public VirtualMemoryWalker {
class PrintRegionWalker : public VirtualMemoryWalker {
private:
ReservedMemoryRegion& _region;
const address _p;
bool _found_region;
const address _p;
outputStream* _st;
public:
FindAndSnapshotRegionWalker(void* p, ReservedMemoryRegion& region) :
_region(region), _p((address)p), _found_region(false) { }
PrintRegionWalker(const void* p, outputStream* st) :
_p((address)p), _st(st) { }
bool do_allocation_site(const ReservedMemoryRegion* rgn) {
if (rgn->contain_address(_p)) {
_region = *rgn;
_found_region = true;
_st->print_cr(PTR_FORMAT " in mmap'd memory region [" PTR_FORMAT " - " PTR_FORMAT "] by %s",
p2i(_p), p2i(rgn->base()), p2i(rgn->base() + rgn->size()), rgn->flag_name());
if (MemTracker::tracking_level() == NMT_detail) {
rgn->call_stack()->print_on(_st);
_st->cr();
}
return false;
}
return true;
}
bool found_region() const { return _found_region; }
};
const bool VirtualMemoryTracker::snapshot_region_contains(void* p, ReservedMemoryRegion& region) {
FindAndSnapshotRegionWalker walker(p, region);
walk_virtual_memory(&walker);
return walker.found_region();
// If p is contained within a known memory region, print information about it to the
// given stream and return true; false otherwise.
bool VirtualMemoryTracker::print_containing_region(const void* p, outputStream* st) {
PrintRegionWalker walker(p, st);
return !walk_virtual_memory(&walker);
}

@ -385,7 +385,9 @@ class VirtualMemoryTracker : AllStatic {
// Walk virtual memory data structure for creating baseline, etc.
static bool walk_virtual_memory(VirtualMemoryWalker* walker);
static const bool snapshot_region_contains(void* p, ReservedMemoryRegion& region);
// If p is contained within a known memory region, print information about it to the
// given stream and return true; false otherwise.
static bool print_containing_region(const void* p, outputStream* st);
// Snapshot current thread stacks
static void snapshot_thread_stacks();

@ -44,7 +44,6 @@
#include "runtime/handles.inline.hpp"
#include "runtime/java.hpp"
#include "runtime/os.hpp"
#include "runtime/safefetch.inline.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubCodeGenerator.hpp"
#include "runtime/stubRoutines.hpp"
@ -483,39 +482,23 @@ extern "C" JNIEXPORT void pp(void* p) {
oop obj = cast_to_oop(p);
obj->print();
} else {
// Ask NMT about this pointer.
// GDB note: We will be using SafeFetch to access the supposed malloc header. If the address is
// not readable, this will generate a signal. That signal will trip up the debugger: gdb will
// catch the signal and disable the pp() command for further use.
// In order to avoid that, switch off SIGSEGV handling with "handle SIGSEGV nostop" before
// invoking pp()
if (MemTracker::enabled()) {
const NMT_TrackingLevel tracking_level = MemTracker::tracking_level();
ReservedMemoryRegion region(0, 0);
// Check and snapshot a mmap'd region that contains the pointer
if (VirtualMemoryTracker::snapshot_region_contains(p, region)) {
tty->print_cr(PTR_FORMAT " in mmap'd memory region [" PTR_FORMAT " - " PTR_FORMAT "] by %s",
p2i(p), p2i(region.base()), p2i(region.base() + region.size()), region.flag_name());
if (tracking_level == NMT_detail) {
region.call_stack()->print_on(tty);
tty->cr();
}
// Does it point into a known mmaped region?
if (VirtualMemoryTracker::print_containing_region(p, tty)) {
return;
}
// Check if it is a malloc'd memory block
if (CanUseSafeFetchN() && SafeFetchN((intptr_t*)p, 0) != 0) {
const MallocHeader* mhdr = (const MallocHeader*)MallocTracker::get_base(p, tracking_level);
char msg[256];
address p_corrupted;
if (SafeFetchN((intptr_t*)mhdr, 0) != 0 && mhdr->check_block_integrity(msg, sizeof(msg), &p_corrupted)) {
tty->print_cr(PTR_FORMAT " malloc'd " SIZE_FORMAT " bytes by %s",
p2i(p), mhdr->size(), NMTUtil::flag_to_name(mhdr->flags()));
if (tracking_level == NMT_detail) {
NativeCallStack ncs;
if (mhdr->get_stack(ncs)) {
ncs.print_on(tty);
tty->cr();
}
}
return;
}
// Does it look like the start of a malloced block?
if (MallocTracker::print_pointer_information(p, tty)) {
return;
}
}
tty->print(PTR_FORMAT, p2i(p));
tty->print_cr(PTR_FORMAT, p2i(p));
}
}