8280289: Enhance debug pp() command with NMT info
Reviewed-by: stuefe, iklam
This commit is contained in:
parent
f35df5bfb5
commit
a59d717fd6
src/hotspot/share
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -31,6 +31,8 @@
|
||||
#include "utilities/debug.hpp"
|
||||
#include "utilities/ostream.hpp"
|
||||
|
||||
#include "jvm_io.h"
|
||||
|
||||
size_t MallocMemorySummary::_snapshot[CALC_OBJ_SIZE_IN_TYPE(MallocMemorySnapshot, size_t)];
|
||||
|
||||
#ifdef ASSERT
|
||||
@ -115,7 +117,7 @@ void MallocHeader::mark_block_as_dead() {
|
||||
void MallocHeader::release() {
|
||||
assert(MemTracker::enabled(), "Sanity");
|
||||
|
||||
check_block_integrity();
|
||||
assert_block_integrity();
|
||||
|
||||
MallocMemorySummary::record_free(size(), flags());
|
||||
MallocMemorySummary::record_free_malloc_header(sizeof(MallocHeader));
|
||||
@ -153,13 +155,18 @@ void MallocHeader::print_block_on_error(outputStream* st, address bad_address) c
|
||||
os::print_hex_dump(st, from1, to2, 1);
|
||||
}
|
||||
}
|
||||
void MallocHeader::assert_block_integrity() const {
|
||||
char msg[256];
|
||||
address corruption = NULL;
|
||||
if (!check_block_integrity(msg, sizeof(msg), &corruption)) {
|
||||
if (corruption != NULL) {
|
||||
print_block_on_error(tty, (address)this);
|
||||
}
|
||||
fatal("NMT corruption: Block at " PTR_FORMAT ": %s", p2i(this), msg);
|
||||
}
|
||||
}
|
||||
|
||||
// Check block integrity. If block is broken, print out a report
|
||||
// to tty (optionally with hex dump surrounding the broken block),
|
||||
// then trigger a fatal error.
|
||||
void MallocHeader::check_block_integrity() const {
|
||||
|
||||
#define PREFIX "NMT corruption: "
|
||||
bool MallocHeader::check_block_integrity(char* msg, size_t msglen, address* p_corruption) const {
|
||||
// Note: if you modify the error messages here, make sure you
|
||||
// adapt the associated gtests too.
|
||||
|
||||
@ -167,7 +174,8 @@ void MallocHeader::check_block_integrity() const {
|
||||
// values. Note that we should not call this for ::free(NULL),
|
||||
// which should be handled by os::free() above us.
|
||||
if (((size_t)p2i(this)) < K) {
|
||||
fatal(PREFIX "Block at " PTR_FORMAT ": invalid block address", p2i(this));
|
||||
jio_snprintf(msg, msglen, "invalid block address");
|
||||
return false;
|
||||
}
|
||||
|
||||
// From here on we assume the block pointer to be valid. We could
|
||||
@ -186,37 +194,42 @@ void MallocHeader::check_block_integrity() const {
|
||||
// Should we ever start using std::max_align_t, this would be one place to
|
||||
// fix up.
|
||||
if (!is_aligned(this, sizeof(uint64_t))) {
|
||||
print_block_on_error(tty, (address)this);
|
||||
fatal(PREFIX "Block at " PTR_FORMAT ": block address is unaligned", p2i(this));
|
||||
*p_corruption = (address)this;
|
||||
jio_snprintf(msg, msglen, "block address is unaligned");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check header canary
|
||||
if (_canary != _header_canary_life_mark) {
|
||||
print_block_on_error(tty, (address)this);
|
||||
fatal(PREFIX "Block at " PTR_FORMAT ": header canary broken.", p2i(this));
|
||||
*p_corruption = (address)this;
|
||||
jio_snprintf(msg, msglen, "header canary broken");
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef _LP64
|
||||
// On 32-bit we have a second canary, check that one too.
|
||||
if (_alt_canary != _header_alt_canary_life_mark) {
|
||||
print_block_on_error(tty, (address)this);
|
||||
fatal(PREFIX "Block at " PTR_FORMAT ": header alternate canary broken.", p2i(this));
|
||||
*p_corruption = (address)this;
|
||||
jio_snprintf(msg, msglen, "header canary broken");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Does block size seems reasonable?
|
||||
if (_size >= max_reasonable_malloc_size) {
|
||||
print_block_on_error(tty, (address)this);
|
||||
fatal(PREFIX "Block at " PTR_FORMAT ": header looks invalid (weirdly large block size)", p2i(this));
|
||||
*p_corruption = (address)this;
|
||||
jio_snprintf(msg, msglen, "header looks invalid (weirdly large block size)");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check footer canary
|
||||
if (get_footer() != _footer_canary_life_mark) {
|
||||
print_block_on_error(tty, footer_address());
|
||||
fatal(PREFIX "Block at " PTR_FORMAT ": footer canary broken at " PTR_FORMAT " (buffer overflow?)",
|
||||
p2i(this), p2i(footer_address()));
|
||||
*p_corruption = footer_address();
|
||||
jio_snprintf(msg, msglen, "footer canary broken at " PTR_FORMAT " (buffer overflow?)",
|
||||
p2i(footer_address()));
|
||||
return false;
|
||||
}
|
||||
#undef PREFIX
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MallocHeader::record_malloc_site(const NativeCallStack& stack, size_t size,
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -314,10 +314,9 @@ class MallocHeader {
|
||||
// We discount sizes larger than these
|
||||
static const size_t max_reasonable_malloc_size = LP64_ONLY(256 * G) NOT_LP64(3500 * M);
|
||||
|
||||
// Check block integrity. If block is broken, print out a report
|
||||
// to tty (optionally with hex dump surrounding the broken block),
|
||||
// then trigger a fatal error.
|
||||
void check_block_integrity() const;
|
||||
// If block is broken, print out a report to tty (optionally with
|
||||
// hex dump surrounding the broken block), then trigger a fatal error
|
||||
void assert_block_integrity() const;
|
||||
void print_block_on_error(outputStream* st, address bad_address) const;
|
||||
void mark_block_as_dead();
|
||||
|
||||
@ -363,6 +362,11 @@ class MallocHeader {
|
||||
// Cleanup tracking information and mark block as dead before the memory is released.
|
||||
void release();
|
||||
|
||||
// If block is broken, fill in a short descriptive text in out,
|
||||
// an option pointer to the corruption in p_corruption, and return false.
|
||||
// Return true if block is fine.
|
||||
bool check_block_integrity(char* msg, size_t msglen, address* p_corruption) const;
|
||||
|
||||
private:
|
||||
inline void set_size(size_t size) {
|
||||
_size = size;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -671,3 +671,29 @@ bool VirtualMemoryTracker::walk_virtual_memory(VirtualMemoryWalker* walker) {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
class FindAndSnapshotRegionWalker : public VirtualMemoryWalker {
|
||||
private:
|
||||
ReservedMemoryRegion& _region;
|
||||
const address _p;
|
||||
bool _found_region;
|
||||
public:
|
||||
FindAndSnapshotRegionWalker(void* p, ReservedMemoryRegion& region) :
|
||||
_region(region), _p((address)p), _found_region(false) { }
|
||||
|
||||
bool do_allocation_site(const ReservedMemoryRegion* rgn) {
|
||||
if (rgn->contain_address(_p)) {
|
||||
_region = *rgn;
|
||||
_found_region = true;
|
||||
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();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -341,7 +341,7 @@ class ReservedMemoryRegion : public VirtualMemoryRegion {
|
||||
return *this;
|
||||
}
|
||||
|
||||
const char* flag_name() { return NMTUtil::flag_to_name(_flag); }
|
||||
const char* flag_name() const { return NMTUtil::flag_to_name(_flag); }
|
||||
|
||||
private:
|
||||
// The committed region contains the uncommitted region, subtract the uncommitted
|
||||
@ -387,6 +387,8 @@ 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);
|
||||
|
||||
// Snapshot current thread stacks
|
||||
static void snapshot_thread_stacks();
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -44,6 +44,7 @@
|
||||
#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"
|
||||
@ -51,7 +52,9 @@
|
||||
#include "runtime/vframe.hpp"
|
||||
#include "runtime/vm_version.hpp"
|
||||
#include "services/heapDumper.hpp"
|
||||
#include "services/mallocTracker.hpp"
|
||||
#include "services/memTracker.hpp"
|
||||
#include "services/virtualMemoryTracker.hpp"
|
||||
#include "utilities/defaultStream.hpp"
|
||||
#include "utilities/events.hpp"
|
||||
#include "utilities/formatBuffer.hpp"
|
||||
@ -480,6 +483,41 @@ extern "C" JNIEXPORT void pp(void* p) {
|
||||
oop obj = cast_to_oop(p);
|
||||
obj->print();
|
||||
} else {
|
||||
#if INCLUDE_NMT
|
||||
// With NMT
|
||||
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();
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // INCLUDE_NMT
|
||||
tty->print(PTR_FORMAT, p2i(p));
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user