[tools] Teach v8_debug_helper where heap spaces start in ptr-compr mode
v8_debug_helper attempts to flag known object pointers when it can recognize them, even if the memory pointed to is not available in the crash dump. In ptr-compr builds, the first pages of the map space, read-only space, and old space are always at the same offsets within the heap reservation region, so we can more easily detect known objects. Bug: v8:9376 Change-Id: I04e0d2357143d753f575f556e94f8fd42ce9d811 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1783729 Commit-Queue: Seth Brenith <seth.brenith@microsoft.com> Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Cr-Commit-Position: refs/heads/master@{#63624}
This commit is contained in:
parent
2f8361d4f3
commit
0a31d508f1
@ -61,6 +61,10 @@ void CheckProp(const d::ObjectProperty& property, const char* expected_type,
|
||||
CHECK(*reinterpret_cast<TValue*>(property.address) == expected_value);
|
||||
}
|
||||
|
||||
bool StartsWith(std::string full_string, std::string prefix) {
|
||||
return full_string.substr(0, prefix.size()) == prefix;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(GetObjectProperties) {
|
||||
@ -68,12 +72,13 @@ TEST(GetObjectProperties) {
|
||||
v8::Isolate* isolate = CcTest::isolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
LocalContext context;
|
||||
d::Roots roots{0, 0, 0, 0}; // We don't know the heap roots.
|
||||
// Claim we don't know anything about the heap layout.
|
||||
d::HeapAddresses heap_addresses{0, 0, 0, 0};
|
||||
|
||||
v8::Local<v8::Value> v = CompileRun("42");
|
||||
Handle<Object> o = v8::Utils::OpenHandle(*v);
|
||||
d::ObjectPropertiesResultPtr props =
|
||||
d::GetObjectProperties(o->ptr(), &ReadMemory, roots);
|
||||
d::GetObjectProperties(o->ptr(), &ReadMemory, heap_addresses);
|
||||
CHECK(props->type_check_result == d::TypeCheckResult::kSmi);
|
||||
CHECK(props->brief == std::string("42 (0x2a)"));
|
||||
CHECK(props->type == std::string("v8::internal::Smi"));
|
||||
@ -81,7 +86,7 @@ TEST(GetObjectProperties) {
|
||||
|
||||
v = CompileRun("[\"a\", \"bc\"]");
|
||||
o = v8::Utils::OpenHandle(*v);
|
||||
props = d::GetObjectProperties(o->ptr(), &ReadMemory, roots);
|
||||
props = d::GetObjectProperties(o->ptr(), &ReadMemory, heap_addresses);
|
||||
CHECK(props->type_check_result == d::TypeCheckResult::kUsedMap);
|
||||
CHECK(props->type == std::string("v8::internal::JSArray"));
|
||||
CHECK_EQ(props->num_properties, 4);
|
||||
@ -92,9 +97,9 @@ TEST(GetObjectProperties) {
|
||||
CheckProp(*props->properties[3], "v8::internal::Object", "length",
|
||||
static_cast<i::Tagged_t>(IntToSmi(2)));
|
||||
|
||||
// We need to supply a root address for decompression before reading the
|
||||
// We need to supply some valid address for decompression before reading the
|
||||
// elements from the JSArray.
|
||||
roots.any_heap_pointer = o->ptr();
|
||||
heap_addresses.any_heap_pointer = o->ptr();
|
||||
|
||||
i::Tagged_t properties_or_hash =
|
||||
*reinterpret_cast<i::Tagged_t*>(props->properties[1]->address);
|
||||
@ -106,32 +111,38 @@ TEST(GetObjectProperties) {
|
||||
// any ability to read memory.
|
||||
{
|
||||
MemoryFailureRegion failure(0, UINTPTR_MAX);
|
||||
props = d::GetObjectProperties(properties_or_hash, &ReadMemory, roots);
|
||||
props =
|
||||
d::GetObjectProperties(properties_or_hash, &ReadMemory, heap_addresses);
|
||||
CHECK(props->type_check_result ==
|
||||
d::TypeCheckResult::kObjectPointerValidButInaccessible);
|
||||
CHECK(props->type == std::string("v8::internal::HeapObject"));
|
||||
CHECK_EQ(props->num_properties, 1);
|
||||
CheckProp(*props->properties[0], "v8::internal::Map", "map");
|
||||
CHECK(std::string(props->brief).substr(0, 21) ==
|
||||
std::string("maybe EmptyFixedArray"));
|
||||
// "maybe" prefix indicates that GetObjectProperties recognized the offset
|
||||
// within the page as matching a known object, but didn't know whether the
|
||||
// object is on the right page. This response can only happen in builds
|
||||
// without pointer compression, because otherwise heap addresses would be at
|
||||
// deterministic locations within the heap reservation.
|
||||
CHECK(StartsWith(props->brief, "maybe EmptyFixedArray") ||
|
||||
StartsWith(props->brief, "EmptyFixedArray"));
|
||||
|
||||
// Provide a heap root so the API can be more sure.
|
||||
roots.read_only_space =
|
||||
// Provide a heap first page so the API can be more sure.
|
||||
heap_addresses.read_only_space_first_page =
|
||||
reinterpret_cast<uintptr_t>(reinterpret_cast<i::Isolate*>(isolate)
|
||||
->heap()
|
||||
->read_only_space()
|
||||
->first_page());
|
||||
props = d::GetObjectProperties(properties_or_hash, &ReadMemory, roots);
|
||||
props =
|
||||
d::GetObjectProperties(properties_or_hash, &ReadMemory, heap_addresses);
|
||||
CHECK(props->type_check_result ==
|
||||
d::TypeCheckResult::kObjectPointerValidButInaccessible);
|
||||
CHECK(props->type == std::string("v8::internal::HeapObject"));
|
||||
CHECK_EQ(props->num_properties, 1);
|
||||
CheckProp(*props->properties[0], "v8::internal::Map", "map");
|
||||
CHECK(std::string(props->brief).substr(0, 15) ==
|
||||
std::string("EmptyFixedArray"));
|
||||
CHECK(StartsWith(props->brief, "EmptyFixedArray"));
|
||||
}
|
||||
|
||||
props = d::GetObjectProperties(elements, &ReadMemory, roots);
|
||||
props = d::GetObjectProperties(elements, &ReadMemory, heap_addresses);
|
||||
CHECK(props->type_check_result == d::TypeCheckResult::kUsedMap);
|
||||
CHECK(props->type == std::string("v8::internal::FixedArray"));
|
||||
CHECK_EQ(props->num_properties, 3);
|
||||
@ -144,7 +155,8 @@ TEST(GetObjectProperties) {
|
||||
// Get the second string value from the FixedArray.
|
||||
i::Tagged_t second_string_address = *reinterpret_cast<i::Tagged_t*>(
|
||||
props->properties[2]->address + sizeof(i::Tagged_t));
|
||||
props = d::GetObjectProperties(second_string_address, &ReadMemory, roots);
|
||||
props = d::GetObjectProperties(second_string_address, &ReadMemory,
|
||||
heap_addresses);
|
||||
CHECK(props->type_check_result == d::TypeCheckResult::kUsedMap);
|
||||
CHECK(props->type == std::string("v8::internal::SeqOneByteString"));
|
||||
CHECK_EQ(props->num_properties, 4);
|
||||
@ -165,12 +177,12 @@ TEST(GetObjectProperties) {
|
||||
uintptr_t map_address =
|
||||
d::GetObjectProperties(
|
||||
*reinterpret_cast<i::Tagged_t*>(props->properties[0]->address),
|
||||
&ReadMemory, roots)
|
||||
&ReadMemory, heap_addresses)
|
||||
->properties[0]
|
||||
->address;
|
||||
MemoryFailureRegion failure(map_address, map_address + i::Map::kSize);
|
||||
props2 = d::GetObjectProperties(second_string_address, &ReadMemory, roots,
|
||||
"v8::internal::String");
|
||||
props2 = d::GetObjectProperties(second_string_address, &ReadMemory,
|
||||
heap_addresses, "v8::internal::String");
|
||||
CHECK(props2->type_check_result == d::TypeCheckResult::kUsedTypeHint);
|
||||
CHECK(props2->type == std::string("v8::internal::String"));
|
||||
CHECK_EQ(props2->num_properties, 3);
|
||||
@ -183,7 +195,7 @@ TEST(GetObjectProperties) {
|
||||
|
||||
// Try a weak reference.
|
||||
props2 = d::GetObjectProperties(second_string_address | kWeakHeapObjectMask,
|
||||
&ReadMemory, roots);
|
||||
&ReadMemory, heap_addresses);
|
||||
std::string weak_ref_prefix = "weak ref to ";
|
||||
CHECK(weak_ref_prefix + props->brief == props2->brief);
|
||||
CHECK(props2->type_check_result == d::TypeCheckResult::kUsedMap);
|
||||
@ -201,9 +213,8 @@ TEST(GetObjectProperties) {
|
||||
const alphabet = "abcdefghijklmnopqrstuvwxyz";
|
||||
alphabet.substr(3,20) + alphabet.toUpperCase().substr(5,15) + "7")");
|
||||
o = v8::Utils::OpenHandle(*v);
|
||||
props = d::GetObjectProperties(o->ptr(), &ReadMemory, roots);
|
||||
CHECK(std::string(props->brief).substr(0, 38) ==
|
||||
std::string("\"defghijklmnopqrstuvwFGHIJKLMNOPQRST7\""));
|
||||
props = d::GetObjectProperties(o->ptr(), &ReadMemory, heap_addresses);
|
||||
CHECK(StartsWith(props->brief, "\"defghijklmnopqrstuvwFGHIJKLMNOPQRST7\""));
|
||||
|
||||
// Cause a failure when reading the "second" pointer within the top-level
|
||||
// ConsString.
|
||||
@ -211,15 +222,15 @@ TEST(GetObjectProperties) {
|
||||
CheckProp(*props->properties[4], "v8::internal::String", "second");
|
||||
uintptr_t second_address = props->properties[4]->address;
|
||||
MemoryFailureRegion failure(second_address, second_address + 4);
|
||||
props = d::GetObjectProperties(o->ptr(), &ReadMemory, roots);
|
||||
CHECK(std::string(props->brief).substr(0, 40) ==
|
||||
std::string("\"defghijklmnopqrstuvwFGHIJKLMNOPQRST...\""));
|
||||
props = d::GetObjectProperties(o->ptr(), &ReadMemory, heap_addresses);
|
||||
CHECK(
|
||||
StartsWith(props->brief, "\"defghijklmnopqrstuvwFGHIJKLMNOPQRST...\""));
|
||||
}
|
||||
|
||||
// Build a very long string.
|
||||
v = CompileRun("'a'.repeat(1000)");
|
||||
o = v8::Utils::OpenHandle(*v);
|
||||
props = d::GetObjectProperties(o->ptr(), &ReadMemory, roots);
|
||||
props = d::GetObjectProperties(o->ptr(), &ReadMemory, heap_addresses);
|
||||
CHECK(std::string(props->brief).substr(79, 7) == std::string("aa...\" "));
|
||||
}
|
||||
|
||||
|
@ -97,6 +97,14 @@ static void DumpKnownObject(FILE* out, i::Heap* heap, const char* space_name,
|
||||
#undef RO_ROOT_LIST_CASE
|
||||
}
|
||||
|
||||
static void DumpSpaceFirstPageAddress(FILE* out, i::PagedSpace* space) {
|
||||
const char* name = space->name();
|
||||
i::Address first_page = reinterpret_cast<i::Address>(space->first_page());
|
||||
i::Tagged_t compressed = i::CompressTagged(first_page);
|
||||
uintptr_t unsigned_compressed = static_cast<uint32_t>(compressed);
|
||||
i::PrintF(out, " 0x%08" V8PRIxPTR ": \"%s\",\n", unsigned_compressed, name);
|
||||
}
|
||||
|
||||
static int DumpHeapConstants(FILE* out, const char* argv0) {
|
||||
// Start up V8.
|
||||
std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform();
|
||||
@ -164,6 +172,25 @@ static int DumpHeapConstants(FILE* out, const char* argv0) {
|
||||
i::PrintF(out, "}\n");
|
||||
}
|
||||
|
||||
if (COMPRESS_POINTERS_BOOL) {
|
||||
// Dump a list of addresses for the first page of each space that contains
|
||||
// objects in the other tables above. This is only useful if two
|
||||
// assumptions hold:
|
||||
// 1. Those pages are positioned deterministically within the heap
|
||||
// reservation block during snapshot deserialization.
|
||||
// 2. Those pages cannot ever be moved (such as by compaction).
|
||||
i::PrintF(out,
|
||||
"\n# Lower 32 bits of first page addresses for various heap "
|
||||
"spaces.\n");
|
||||
i::PrintF(out, "HEAP_FIRST_PAGES = {\n");
|
||||
i::PagedSpaceIterator it(heap);
|
||||
for (i::PagedSpace* s = it.Next(); s != nullptr; s = it.Next()) {
|
||||
DumpSpaceFirstPageAddress(out, s);
|
||||
}
|
||||
DumpSpaceFirstPageAddress(out, read_only_heap->read_only_space());
|
||||
i::PrintF(out, "}\n");
|
||||
}
|
||||
|
||||
// Dump frame markers
|
||||
i::PrintF(out, "\n# List of known V8 Frame Markers.\n");
|
||||
#define DUMP_MARKER(T, class) i::PrintF(out, " \"%s\",\n", #T);
|
||||
|
@ -109,7 +109,7 @@ typedef MemoryAccessResult (*MemoryAccessor)(uintptr_t address,
|
||||
// Additional data that can help GetObjectProperties to be more accurate. Any
|
||||
// fields you don't know can be set to zero and this library will do the best it
|
||||
// can with the information available.
|
||||
struct Roots {
|
||||
struct HeapAddresses {
|
||||
// Beginning of allocated space for various kinds of data. These can help us
|
||||
// to detect certain common objects that are placed in memory during startup.
|
||||
// These values might be provided via name-value pairs in CrashPad dumps.
|
||||
@ -119,9 +119,9 @@ struct Roots {
|
||||
// key stored in v8::internal::Isolate::isolate_key_.
|
||||
// 2. Get isolate->heap_.map_space_->memory_chunk_list_.front_ and similar for
|
||||
// old_space_ and read_only_space_.
|
||||
uintptr_t map_space;
|
||||
uintptr_t old_space;
|
||||
uintptr_t read_only_space;
|
||||
uintptr_t map_space_first_page;
|
||||
uintptr_t old_space_first_page;
|
||||
uintptr_t read_only_space_first_page;
|
||||
|
||||
// Any valid heap pointer address. On platforms where pointer compression is
|
||||
// enabled, this can allow us to get data from compressed pointers even if the
|
||||
@ -139,7 +139,8 @@ extern "C" {
|
||||
V8_DEBUG_HELPER_EXPORT v8::debug_helper::ObjectPropertiesResult*
|
||||
_v8_debug_helper_GetObjectProperties(
|
||||
uintptr_t object, v8::debug_helper::MemoryAccessor memory_accessor,
|
||||
const v8::debug_helper::Roots& heap_roots, const char* type_hint);
|
||||
const v8::debug_helper::HeapAddresses& heap_addresses,
|
||||
const char* type_hint);
|
||||
V8_DEBUG_HELPER_EXPORT void _v8_debug_helper_Free_ObjectPropertiesResult(
|
||||
v8::debug_helper::ObjectPropertiesResult* result);
|
||||
}
|
||||
@ -166,9 +167,9 @@ using ObjectPropertiesResultPtr =
|
||||
// v8::internal::Object.
|
||||
inline ObjectPropertiesResultPtr GetObjectProperties(
|
||||
uintptr_t object, v8::debug_helper::MemoryAccessor memory_accessor,
|
||||
const Roots& heap_roots, const char* type_hint = nullptr) {
|
||||
const HeapAddresses& heap_addresses, const char* type_hint = nullptr) {
|
||||
return ObjectPropertiesResultPtr(_v8_debug_helper_GetObjectProperties(
|
||||
object, memory_accessor, heap_roots, type_hint));
|
||||
object, memory_accessor, heap_addresses, type_hint));
|
||||
}
|
||||
|
||||
} // namespace debug_helper
|
||||
|
@ -16,6 +16,9 @@ out = """
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include "src/common/ptr-compr-inl.h"
|
||||
#include "tools/debug_helper/debug-helper-internal.h"
|
||||
|
||||
namespace v8_debug_helper_internal {
|
||||
"""
|
||||
|
||||
@ -51,6 +54,25 @@ def iterate_maps(target_space, camel_space_name):
|
||||
iterate_maps('map_space', 'MapSpace')
|
||||
iterate_maps('read_only_space', 'ReadOnlySpace')
|
||||
|
||||
out = out + '\nvoid FillInUnknownHeapAddresses(' + \
|
||||
'd::HeapAddresses* heap_addresses, uintptr_t any_uncompressed_ptr) {\n'
|
||||
if (hasattr(v8heapconst, 'HEAP_FIRST_PAGES')): # Only exists in ptr-compr builds.
|
||||
out = out + ' if (heap_addresses->any_heap_pointer == 0) {\n'
|
||||
out = out + ' heap_addresses->any_heap_pointer = any_uncompressed_ptr;\n'
|
||||
out = out + ' }\n'
|
||||
expected_spaces = set(['map_space', 'read_only_space', 'old_space'])
|
||||
for offset, space_name in v8heapconst.HEAP_FIRST_PAGES.items():
|
||||
# Turn 32-bit unsigned value into signed.
|
||||
if offset >= 0x80000000:
|
||||
offset -= 0x100000000
|
||||
if (space_name in expected_spaces):
|
||||
out = out + ' if (heap_addresses->' + space_name + '_first_page == 0) {\n'
|
||||
out = out + ' heap_addresses->' + space_name + \
|
||||
'_first_page = i::DecompressTaggedPointer(any_uncompressed_ptr, ' + \
|
||||
str(offset) + ');\n'
|
||||
out = out + ' }\n'
|
||||
out = out + '}\n'
|
||||
|
||||
out = out + '\n}\n'
|
||||
|
||||
try:
|
||||
|
@ -241,10 +241,10 @@ TypedObject GetTypedHeapObject(uintptr_t address, d::MemoryAccessor accessor,
|
||||
return GetTypedObjectByHint(address, type_hint);
|
||||
} else {
|
||||
// TODO(v8:9376): Use known maps here. If known map is just a guess (because
|
||||
// root pointers weren't provided), then create a synthetic property with
|
||||
// the more specific type. Then the caller could presumably ask us again
|
||||
// with the type hint we provided. Otherwise, just go ahead and use it to
|
||||
// generate properties.
|
||||
// heap page addresses weren't provided), then create a synthetic property
|
||||
// with the more specific type. Then the caller could presumably ask us
|
||||
// again with the type hint we provided. Otherwise, just go ahead and use it
|
||||
// to generate properties.
|
||||
return {type.validity == d::MemoryAccessResult::kAddressNotValid
|
||||
? d::TypeCheckResult::kMapPointerInvalid
|
||||
: d::TypeCheckResult::kMapPointerValidButInaccessible,
|
||||
@ -447,19 +447,24 @@ std::unique_ptr<ObjectPropertiesResult> GetHeapObjectProperties(
|
||||
}
|
||||
|
||||
std::unique_ptr<ObjectPropertiesResult> GetHeapObjectProperties(
|
||||
uintptr_t address, d::MemoryAccessor memory_accessor, const d::Roots& roots,
|
||||
const char* type_hint) {
|
||||
uintptr_t address, d::MemoryAccessor memory_accessor,
|
||||
d::HeapAddresses heap_addresses, const char* type_hint) {
|
||||
// Try to figure out the heap range, for pointer compression (this is unused
|
||||
// if pointer compression is disabled).
|
||||
uintptr_t any_uncompressed_ptr = 0;
|
||||
if (!IsPointerCompressed(address)) any_uncompressed_ptr = address;
|
||||
if (any_uncompressed_ptr == 0) any_uncompressed_ptr = roots.any_heap_pointer;
|
||||
if (any_uncompressed_ptr == 0) any_uncompressed_ptr = roots.map_space;
|
||||
if (any_uncompressed_ptr == 0) any_uncompressed_ptr = roots.old_space;
|
||||
if (any_uncompressed_ptr == 0) any_uncompressed_ptr = roots.read_only_space;
|
||||
if (any_uncompressed_ptr == 0)
|
||||
any_uncompressed_ptr = heap_addresses.any_heap_pointer;
|
||||
if (any_uncompressed_ptr == 0)
|
||||
any_uncompressed_ptr = heap_addresses.map_space_first_page;
|
||||
if (any_uncompressed_ptr == 0)
|
||||
any_uncompressed_ptr = heap_addresses.old_space_first_page;
|
||||
if (any_uncompressed_ptr == 0)
|
||||
any_uncompressed_ptr = heap_addresses.read_only_space_first_page;
|
||||
FillInUnknownHeapAddresses(&heap_addresses, any_uncompressed_ptr);
|
||||
if (any_uncompressed_ptr == 0) {
|
||||
// We can't figure out the heap range. Just check for known objects.
|
||||
std::string brief = FindKnownObject(address, roots);
|
||||
std::string brief = FindKnownObject(address, heap_addresses);
|
||||
brief = AppendAddressAndType(brief, address, "v8::internal::TaggedValue");
|
||||
return v8::base::make_unique<ObjectPropertiesResult>(
|
||||
d::TypeCheckResult::kUnableToDecompress, brief,
|
||||
@ -467,22 +472,18 @@ std::unique_ptr<ObjectPropertiesResult> GetHeapObjectProperties(
|
||||
std::vector<std::unique_ptr<ObjectProperty>>());
|
||||
}
|
||||
|
||||
// TODO(v8:9376): It seems that the space roots are at predictable offsets
|
||||
// within the heap reservation block when pointer compression is enabled, so
|
||||
// we should be able to set those here.
|
||||
|
||||
address = Decompress(address, any_uncompressed_ptr);
|
||||
// From here on all addresses should be decompressed.
|
||||
|
||||
// Regardless of whether we can read the object itself, maybe we can find its
|
||||
// pointer in the list of known objects.
|
||||
std::string brief = FindKnownObject(address, roots);
|
||||
std::string brief = FindKnownObject(address, heap_addresses);
|
||||
return GetHeapObjectProperties(address, memory_accessor, type_hint, brief);
|
||||
}
|
||||
|
||||
std::unique_ptr<ObjectPropertiesResult> GetObjectPropertiesImpl(
|
||||
uintptr_t address, d::MemoryAccessor memory_accessor, const d::Roots& roots,
|
||||
const char* type_hint) {
|
||||
uintptr_t address, d::MemoryAccessor memory_accessor,
|
||||
const d::HeapAddresses& heap_addresses, const char* type_hint) {
|
||||
std::vector<std::unique_ptr<ObjectProperty>> props;
|
||||
if (static_cast<uint32_t>(address) == i::kClearedWeakHeapObjectLower32) {
|
||||
return v8::base::make_unique<ObjectPropertiesResult>(
|
||||
@ -494,8 +495,8 @@ std::unique_ptr<ObjectPropertiesResult> GetObjectPropertiesImpl(
|
||||
address &= ~i::kWeakHeapObjectMask;
|
||||
}
|
||||
if (i::Internals::HasHeapObjectTag(address)) {
|
||||
std::unique_ptr<ObjectPropertiesResult> result =
|
||||
GetHeapObjectProperties(address, memory_accessor, roots, type_hint);
|
||||
std::unique_ptr<ObjectPropertiesResult> result = GetHeapObjectProperties(
|
||||
address, memory_accessor, heap_addresses, type_hint);
|
||||
if (is_weak) {
|
||||
result->Prepend("weak ref to ");
|
||||
}
|
||||
@ -520,9 +521,9 @@ extern "C" {
|
||||
V8_DEBUG_HELPER_EXPORT d::ObjectPropertiesResult*
|
||||
_v8_debug_helper_GetObjectProperties(uintptr_t object,
|
||||
d::MemoryAccessor memory_accessor,
|
||||
const d::Roots& heap_roots,
|
||||
const d::HeapAddresses& heap_addresses,
|
||||
const char* type_hint) {
|
||||
return di::GetObjectPropertiesImpl(object, memory_accessor, heap_roots,
|
||||
return di::GetObjectPropertiesImpl(object, memory_accessor, heap_addresses,
|
||||
type_hint)
|
||||
.release()
|
||||
->GetPublicView();
|
||||
|
@ -9,36 +9,37 @@ namespace d = v8::debug_helper;
|
||||
|
||||
namespace v8_debug_helper_internal {
|
||||
|
||||
std::string FindKnownObject(uintptr_t address, const d::Roots& roots) {
|
||||
std::string FindKnownObject(uintptr_t address,
|
||||
const d::HeapAddresses& heap_addresses) {
|
||||
uintptr_t containing_page = address & ~i::kPageAlignmentMask;
|
||||
uintptr_t offset_in_page = address & i::kPageAlignmentMask;
|
||||
|
||||
// If there's a match with a known root, then search only that page.
|
||||
if (containing_page == roots.map_space) {
|
||||
// If there's a match with a known page, then search only that page.
|
||||
if (containing_page == heap_addresses.map_space_first_page) {
|
||||
return FindKnownObjectInMapSpace(offset_in_page);
|
||||
}
|
||||
if (containing_page == roots.old_space) {
|
||||
if (containing_page == heap_addresses.old_space_first_page) {
|
||||
return FindKnownObjectInOldSpace(offset_in_page);
|
||||
}
|
||||
if (containing_page == roots.read_only_space) {
|
||||
if (containing_page == heap_addresses.read_only_space_first_page) {
|
||||
return FindKnownObjectInReadOnlySpace(offset_in_page);
|
||||
}
|
||||
|
||||
// For any unknown roots, compile a list of things this object might be.
|
||||
// For any unknown pages, compile a list of things this object might be.
|
||||
std::string result;
|
||||
if (roots.map_space == 0) {
|
||||
if (heap_addresses.map_space_first_page == 0) {
|
||||
std::string sub_result = FindKnownObjectInMapSpace(offset_in_page);
|
||||
if (!sub_result.empty()) {
|
||||
result += "maybe " + sub_result;
|
||||
}
|
||||
}
|
||||
if (roots.old_space == 0) {
|
||||
if (heap_addresses.old_space_first_page == 0) {
|
||||
std::string sub_result = FindKnownObjectInOldSpace(offset_in_page);
|
||||
if (!sub_result.empty()) {
|
||||
result = (result.empty() ? "" : result + ", ") + "maybe " + sub_result;
|
||||
}
|
||||
}
|
||||
if (roots.read_only_space == 0) {
|
||||
if (heap_addresses.read_only_space_first_page == 0) {
|
||||
std::string sub_result = FindKnownObjectInReadOnlySpace(offset_in_page);
|
||||
if (!sub_result.empty()) {
|
||||
result = (result.empty() ? "" : result + ", ") + "maybe " + sub_result;
|
||||
|
@ -14,14 +14,17 @@ namespace d = v8::debug_helper;
|
||||
|
||||
namespace v8_debug_helper_internal {
|
||||
|
||||
// Functions generated by mkgrokdump:
|
||||
// Functions generated by gen-heap-constants.py, based on data from mkgrokdump:
|
||||
std::string FindKnownObjectInOldSpace(uintptr_t offset);
|
||||
std::string FindKnownObjectInReadOnlySpace(uintptr_t offset);
|
||||
std::string FindKnownObjectInMapSpace(uintptr_t offset);
|
||||
std::string FindKnownMapInstanceTypeInMapSpace(uintptr_t offset);
|
||||
std::string FindKnownMapInstanceTypeInReadOnlySpace(uintptr_t offset);
|
||||
void FillInUnknownHeapAddresses(d::HeapAddresses* heap_addresses,
|
||||
uintptr_t any_uncompressed_ptr);
|
||||
|
||||
std::string FindKnownObject(uintptr_t address, const d::Roots& roots);
|
||||
std::string FindKnownObject(uintptr_t address,
|
||||
const d::HeapAddresses& heap_addresses);
|
||||
|
||||
} // namespace v8_debug_helper_internal
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user