Commit 0a31d508 authored by Seth Brenith's avatar Seth Brenith Committed by Commit Bot

[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: 's avatarUlan Degenbaev <ulan@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#63624}
parent 2f8361d4
...@@ -61,6 +61,10 @@ void CheckProp(const d::ObjectProperty& property, const char* expected_type, ...@@ -61,6 +61,10 @@ void CheckProp(const d::ObjectProperty& property, const char* expected_type,
CHECK(*reinterpret_cast<TValue*>(property.address) == expected_value); 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 } // namespace
TEST(GetObjectProperties) { TEST(GetObjectProperties) {
...@@ -68,12 +72,13 @@ TEST(GetObjectProperties) { ...@@ -68,12 +72,13 @@ TEST(GetObjectProperties) {
v8::Isolate* isolate = CcTest::isolate(); v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope scope(isolate); v8::HandleScope scope(isolate);
LocalContext context; 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"); v8::Local<v8::Value> v = CompileRun("42");
Handle<Object> o = v8::Utils::OpenHandle(*v); Handle<Object> o = v8::Utils::OpenHandle(*v);
d::ObjectPropertiesResultPtr props = 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->type_check_result == d::TypeCheckResult::kSmi);
CHECK(props->brief == std::string("42 (0x2a)")); CHECK(props->brief == std::string("42 (0x2a)"));
CHECK(props->type == std::string("v8::internal::Smi")); CHECK(props->type == std::string("v8::internal::Smi"));
...@@ -81,7 +86,7 @@ TEST(GetObjectProperties) { ...@@ -81,7 +86,7 @@ TEST(GetObjectProperties) {
v = CompileRun("[\"a\", \"bc\"]"); v = CompileRun("[\"a\", \"bc\"]");
o = v8::Utils::OpenHandle(*v); 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_check_result == d::TypeCheckResult::kUsedMap);
CHECK(props->type == std::string("v8::internal::JSArray")); CHECK(props->type == std::string("v8::internal::JSArray"));
CHECK_EQ(props->num_properties, 4); CHECK_EQ(props->num_properties, 4);
...@@ -92,9 +97,9 @@ TEST(GetObjectProperties) { ...@@ -92,9 +97,9 @@ TEST(GetObjectProperties) {
CheckProp(*props->properties[3], "v8::internal::Object", "length", CheckProp(*props->properties[3], "v8::internal::Object", "length",
static_cast<i::Tagged_t>(IntToSmi(2))); 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. // elements from the JSArray.
roots.any_heap_pointer = o->ptr(); heap_addresses.any_heap_pointer = o->ptr();
i::Tagged_t properties_or_hash = i::Tagged_t properties_or_hash =
*reinterpret_cast<i::Tagged_t*>(props->properties[1]->address); *reinterpret_cast<i::Tagged_t*>(props->properties[1]->address);
...@@ -106,32 +111,38 @@ TEST(GetObjectProperties) { ...@@ -106,32 +111,38 @@ TEST(GetObjectProperties) {
// any ability to read memory. // any ability to read memory.
{ {
MemoryFailureRegion failure(0, UINTPTR_MAX); 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 == CHECK(props->type_check_result ==
d::TypeCheckResult::kObjectPointerValidButInaccessible); d::TypeCheckResult::kObjectPointerValidButInaccessible);
CHECK(props->type == std::string("v8::internal::HeapObject")); CHECK(props->type == std::string("v8::internal::HeapObject"));
CHECK_EQ(props->num_properties, 1); CHECK_EQ(props->num_properties, 1);
CheckProp(*props->properties[0], "v8::internal::Map", "map"); CheckProp(*props->properties[0], "v8::internal::Map", "map");
CHECK(std::string(props->brief).substr(0, 21) == // "maybe" prefix indicates that GetObjectProperties recognized the offset
std::string("maybe EmptyFixedArray")); // 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
// Provide a heap root so the API can be more sure. // without pointer compression, because otherwise heap addresses would be at
roots.read_only_space = // deterministic locations within the heap reservation.
CHECK(StartsWith(props->brief, "maybe EmptyFixedArray") ||
StartsWith(props->brief, "EmptyFixedArray"));
// 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) reinterpret_cast<uintptr_t>(reinterpret_cast<i::Isolate*>(isolate)
->heap() ->heap()
->read_only_space() ->read_only_space()
->first_page()); ->first_page());
props = d::GetObjectProperties(properties_or_hash, &ReadMemory, roots); props =
d::GetObjectProperties(properties_or_hash, &ReadMemory, heap_addresses);
CHECK(props->type_check_result == CHECK(props->type_check_result ==
d::TypeCheckResult::kObjectPointerValidButInaccessible); d::TypeCheckResult::kObjectPointerValidButInaccessible);
CHECK(props->type == std::string("v8::internal::HeapObject")); CHECK(props->type == std::string("v8::internal::HeapObject"));
CHECK_EQ(props->num_properties, 1); CHECK_EQ(props->num_properties, 1);
CheckProp(*props->properties[0], "v8::internal::Map", "map"); CheckProp(*props->properties[0], "v8::internal::Map", "map");
CHECK(std::string(props->brief).substr(0, 15) == CHECK(StartsWith(props->brief, "EmptyFixedArray"));
std::string("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_check_result == d::TypeCheckResult::kUsedMap);
CHECK(props->type == std::string("v8::internal::FixedArray")); CHECK(props->type == std::string("v8::internal::FixedArray"));
CHECK_EQ(props->num_properties, 3); CHECK_EQ(props->num_properties, 3);
...@@ -144,7 +155,8 @@ TEST(GetObjectProperties) { ...@@ -144,7 +155,8 @@ TEST(GetObjectProperties) {
// Get the second string value from the FixedArray. // Get the second string value from the FixedArray.
i::Tagged_t second_string_address = *reinterpret_cast<i::Tagged_t*>( i::Tagged_t second_string_address = *reinterpret_cast<i::Tagged_t*>(
props->properties[2]->address + sizeof(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_check_result == d::TypeCheckResult::kUsedMap);
CHECK(props->type == std::string("v8::internal::SeqOneByteString")); CHECK(props->type == std::string("v8::internal::SeqOneByteString"));
CHECK_EQ(props->num_properties, 4); CHECK_EQ(props->num_properties, 4);
...@@ -165,12 +177,12 @@ TEST(GetObjectProperties) { ...@@ -165,12 +177,12 @@ TEST(GetObjectProperties) {
uintptr_t map_address = uintptr_t map_address =
d::GetObjectProperties( d::GetObjectProperties(
*reinterpret_cast<i::Tagged_t*>(props->properties[0]->address), *reinterpret_cast<i::Tagged_t*>(props->properties[0]->address),
&ReadMemory, roots) &ReadMemory, heap_addresses)
->properties[0] ->properties[0]
->address; ->address;
MemoryFailureRegion failure(map_address, map_address + i::Map::kSize); MemoryFailureRegion failure(map_address, map_address + i::Map::kSize);
props2 = d::GetObjectProperties(second_string_address, &ReadMemory, roots, props2 = d::GetObjectProperties(second_string_address, &ReadMemory,
"v8::internal::String"); heap_addresses, "v8::internal::String");
CHECK(props2->type_check_result == d::TypeCheckResult::kUsedTypeHint); CHECK(props2->type_check_result == d::TypeCheckResult::kUsedTypeHint);
CHECK(props2->type == std::string("v8::internal::String")); CHECK(props2->type == std::string("v8::internal::String"));
CHECK_EQ(props2->num_properties, 3); CHECK_EQ(props2->num_properties, 3);
...@@ -183,7 +195,7 @@ TEST(GetObjectProperties) { ...@@ -183,7 +195,7 @@ TEST(GetObjectProperties) {
// Try a weak reference. // Try a weak reference.
props2 = d::GetObjectProperties(second_string_address | kWeakHeapObjectMask, props2 = d::GetObjectProperties(second_string_address | kWeakHeapObjectMask,
&ReadMemory, roots); &ReadMemory, heap_addresses);
std::string weak_ref_prefix = "weak ref to "; std::string weak_ref_prefix = "weak ref to ";
CHECK(weak_ref_prefix + props->brief == props2->brief); CHECK(weak_ref_prefix + props->brief == props2->brief);
CHECK(props2->type_check_result == d::TypeCheckResult::kUsedMap); CHECK(props2->type_check_result == d::TypeCheckResult::kUsedMap);
...@@ -201,9 +213,8 @@ TEST(GetObjectProperties) { ...@@ -201,9 +213,8 @@ TEST(GetObjectProperties) {
const alphabet = "abcdefghijklmnopqrstuvwxyz"; const alphabet = "abcdefghijklmnopqrstuvwxyz";
alphabet.substr(3,20) + alphabet.toUpperCase().substr(5,15) + "7")"); alphabet.substr(3,20) + alphabet.toUpperCase().substr(5,15) + "7")");
o = v8::Utils::OpenHandle(*v); 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(0, 38) == CHECK(StartsWith(props->brief, "\"defghijklmnopqrstuvwFGHIJKLMNOPQRST7\""));
std::string("\"defghijklmnopqrstuvwFGHIJKLMNOPQRST7\""));
// Cause a failure when reading the "second" pointer within the top-level // Cause a failure when reading the "second" pointer within the top-level
// ConsString. // ConsString.
...@@ -211,15 +222,15 @@ TEST(GetObjectProperties) { ...@@ -211,15 +222,15 @@ TEST(GetObjectProperties) {
CheckProp(*props->properties[4], "v8::internal::String", "second"); CheckProp(*props->properties[4], "v8::internal::String", "second");
uintptr_t second_address = props->properties[4]->address; uintptr_t second_address = props->properties[4]->address;
MemoryFailureRegion failure(second_address, second_address + 4); MemoryFailureRegion failure(second_address, second_address + 4);
props = d::GetObjectProperties(o->ptr(), &ReadMemory, roots); props = d::GetObjectProperties(o->ptr(), &ReadMemory, heap_addresses);
CHECK(std::string(props->brief).substr(0, 40) == CHECK(
std::string("\"defghijklmnopqrstuvwFGHIJKLMNOPQRST...\"")); StartsWith(props->brief, "\"defghijklmnopqrstuvwFGHIJKLMNOPQRST...\""));
} }
// Build a very long string. // Build a very long string.
v = CompileRun("'a'.repeat(1000)"); v = CompileRun("'a'.repeat(1000)");
o = v8::Utils::OpenHandle(*v); 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...\" ")); 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, ...@@ -97,6 +97,14 @@ static void DumpKnownObject(FILE* out, i::Heap* heap, const char* space_name,
#undef RO_ROOT_LIST_CASE #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) { static int DumpHeapConstants(FILE* out, const char* argv0) {
// Start up V8. // Start up V8.
std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform(); std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform();
...@@ -164,6 +172,25 @@ static int DumpHeapConstants(FILE* out, const char* argv0) { ...@@ -164,6 +172,25 @@ static int DumpHeapConstants(FILE* out, const char* argv0) {
i::PrintF(out, "}\n"); 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 // Dump frame markers
i::PrintF(out, "\n# List of known V8 Frame Markers.\n"); i::PrintF(out, "\n# List of known V8 Frame Markers.\n");
#define DUMP_MARKER(T, class) i::PrintF(out, " \"%s\",\n", #T); #define DUMP_MARKER(T, class) i::PrintF(out, " \"%s\",\n", #T);
......
...@@ -109,7 +109,7 @@ typedef MemoryAccessResult (*MemoryAccessor)(uintptr_t address, ...@@ -109,7 +109,7 @@ typedef MemoryAccessResult (*MemoryAccessor)(uintptr_t address,
// Additional data that can help GetObjectProperties to be more accurate. Any // 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 // fields you don't know can be set to zero and this library will do the best it
// can with the information available. // can with the information available.
struct Roots { struct HeapAddresses {
// Beginning of allocated space for various kinds of data. These can help us // 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. // to detect certain common objects that are placed in memory during startup.
// These values might be provided via name-value pairs in CrashPad dumps. // These values might be provided via name-value pairs in CrashPad dumps.
...@@ -119,9 +119,9 @@ struct Roots { ...@@ -119,9 +119,9 @@ struct Roots {
// key stored in v8::internal::Isolate::isolate_key_. // key stored in v8::internal::Isolate::isolate_key_.
// 2. Get isolate->heap_.map_space_->memory_chunk_list_.front_ and similar for // 2. Get isolate->heap_.map_space_->memory_chunk_list_.front_ and similar for
// old_space_ and read_only_space_. // old_space_ and read_only_space_.
uintptr_t map_space; uintptr_t map_space_first_page;
uintptr_t old_space; uintptr_t old_space_first_page;
uintptr_t read_only_space; uintptr_t read_only_space_first_page;
// Any valid heap pointer address. On platforms where pointer compression is // 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 // enabled, this can allow us to get data from compressed pointers even if the
...@@ -139,7 +139,8 @@ extern "C" { ...@@ -139,7 +139,8 @@ extern "C" {
V8_DEBUG_HELPER_EXPORT v8::debug_helper::ObjectPropertiesResult* V8_DEBUG_HELPER_EXPORT v8::debug_helper::ObjectPropertiesResult*
_v8_debug_helper_GetObjectProperties( _v8_debug_helper_GetObjectProperties(
uintptr_t object, v8::debug_helper::MemoryAccessor memory_accessor, 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_EXPORT void _v8_debug_helper_Free_ObjectPropertiesResult(
v8::debug_helper::ObjectPropertiesResult* result); v8::debug_helper::ObjectPropertiesResult* result);
} }
...@@ -166,9 +167,9 @@ using ObjectPropertiesResultPtr = ...@@ -166,9 +167,9 @@ using ObjectPropertiesResultPtr =
// v8::internal::Object. // v8::internal::Object.
inline ObjectPropertiesResultPtr GetObjectProperties( inline ObjectPropertiesResultPtr GetObjectProperties(
uintptr_t object, v8::debug_helper::MemoryAccessor memory_accessor, 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( return ObjectPropertiesResultPtr(_v8_debug_helper_GetObjectProperties(
object, memory_accessor, heap_roots, type_hint)); object, memory_accessor, heap_addresses, type_hint));
} }
} // namespace debug_helper } // namespace debug_helper
......
...@@ -16,6 +16,9 @@ out = """ ...@@ -16,6 +16,9 @@ out = """
#include <cstdint> #include <cstdint>
#include <string> #include <string>
#include "src/common/ptr-compr-inl.h"
#include "tools/debug_helper/debug-helper-internal.h"
namespace v8_debug_helper_internal { namespace v8_debug_helper_internal {
""" """
...@@ -51,6 +54,25 @@ def iterate_maps(target_space, camel_space_name): ...@@ -51,6 +54,25 @@ def iterate_maps(target_space, camel_space_name):
iterate_maps('map_space', 'MapSpace') iterate_maps('map_space', 'MapSpace')
iterate_maps('read_only_space', 'ReadOnlySpace') 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' out = out + '\n}\n'
try: try:
......
...@@ -241,10 +241,10 @@ TypedObject GetTypedHeapObject(uintptr_t address, d::MemoryAccessor accessor, ...@@ -241,10 +241,10 @@ TypedObject GetTypedHeapObject(uintptr_t address, d::MemoryAccessor accessor,
return GetTypedObjectByHint(address, type_hint); return GetTypedObjectByHint(address, type_hint);
} else { } else {
// TODO(v8:9376): Use known maps here. If known map is just a guess (because // 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 // heap page addresses weren't provided), then create a synthetic property
// the more specific type. Then the caller could presumably ask us again // with the more specific type. Then the caller could presumably ask us
// with the type hint we provided. Otherwise, just go ahead and use it to // again with the type hint we provided. Otherwise, just go ahead and use it
// generate properties. // to generate properties.
return {type.validity == d::MemoryAccessResult::kAddressNotValid return {type.validity == d::MemoryAccessResult::kAddressNotValid
? d::TypeCheckResult::kMapPointerInvalid ? d::TypeCheckResult::kMapPointerInvalid
: d::TypeCheckResult::kMapPointerValidButInaccessible, : d::TypeCheckResult::kMapPointerValidButInaccessible,
...@@ -447,19 +447,24 @@ std::unique_ptr<ObjectPropertiesResult> GetHeapObjectProperties( ...@@ -447,19 +447,24 @@ std::unique_ptr<ObjectPropertiesResult> GetHeapObjectProperties(
} }
std::unique_ptr<ObjectPropertiesResult> GetHeapObjectProperties( std::unique_ptr<ObjectPropertiesResult> GetHeapObjectProperties(
uintptr_t address, d::MemoryAccessor memory_accessor, const d::Roots& roots, uintptr_t address, d::MemoryAccessor memory_accessor,
const char* type_hint) { d::HeapAddresses heap_addresses, const char* type_hint) {
// Try to figure out the heap range, for pointer compression (this is unused // Try to figure out the heap range, for pointer compression (this is unused
// if pointer compression is disabled). // if pointer compression is disabled).
uintptr_t any_uncompressed_ptr = 0; uintptr_t any_uncompressed_ptr = 0;
if (!IsPointerCompressed(address)) any_uncompressed_ptr = address; if (!IsPointerCompressed(address)) any_uncompressed_ptr = address;
if (any_uncompressed_ptr == 0) any_uncompressed_ptr = roots.any_heap_pointer; if (any_uncompressed_ptr == 0)
if (any_uncompressed_ptr == 0) any_uncompressed_ptr = roots.map_space; any_uncompressed_ptr = heap_addresses.any_heap_pointer;
if (any_uncompressed_ptr == 0) any_uncompressed_ptr = roots.old_space; if (any_uncompressed_ptr == 0)
if (any_uncompressed_ptr == 0) any_uncompressed_ptr = roots.read_only_space; 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) { if (any_uncompressed_ptr == 0) {
// We can't figure out the heap range. Just check for known objects. // 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"); brief = AppendAddressAndType(brief, address, "v8::internal::TaggedValue");
return v8::base::make_unique<ObjectPropertiesResult>( return v8::base::make_unique<ObjectPropertiesResult>(
d::TypeCheckResult::kUnableToDecompress, brief, d::TypeCheckResult::kUnableToDecompress, brief,
...@@ -467,22 +472,18 @@ std::unique_ptr<ObjectPropertiesResult> GetHeapObjectProperties( ...@@ -467,22 +472,18 @@ std::unique_ptr<ObjectPropertiesResult> GetHeapObjectProperties(
std::vector<std::unique_ptr<ObjectProperty>>()); 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); address = Decompress(address, any_uncompressed_ptr);
// From here on all addresses should be decompressed. // From here on all addresses should be decompressed.
// Regardless of whether we can read the object itself, maybe we can find its // Regardless of whether we can read the object itself, maybe we can find its
// pointer in the list of known objects. // 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); return GetHeapObjectProperties(address, memory_accessor, type_hint, brief);
} }
std::unique_ptr<ObjectPropertiesResult> GetObjectPropertiesImpl( std::unique_ptr<ObjectPropertiesResult> GetObjectPropertiesImpl(
uintptr_t address, d::MemoryAccessor memory_accessor, const d::Roots& roots, uintptr_t address, d::MemoryAccessor memory_accessor,
const char* type_hint) { const d::HeapAddresses& heap_addresses, const char* type_hint) {
std::vector<std::unique_ptr<ObjectProperty>> props; std::vector<std::unique_ptr<ObjectProperty>> props;
if (static_cast<uint32_t>(address) == i::kClearedWeakHeapObjectLower32) { if (static_cast<uint32_t>(address) == i::kClearedWeakHeapObjectLower32) {
return v8::base::make_unique<ObjectPropertiesResult>( return v8::base::make_unique<ObjectPropertiesResult>(
...@@ -494,8 +495,8 @@ std::unique_ptr<ObjectPropertiesResult> GetObjectPropertiesImpl( ...@@ -494,8 +495,8 @@ std::unique_ptr<ObjectPropertiesResult> GetObjectPropertiesImpl(
address &= ~i::kWeakHeapObjectMask; address &= ~i::kWeakHeapObjectMask;
} }
if (i::Internals::HasHeapObjectTag(address)) { if (i::Internals::HasHeapObjectTag(address)) {
std::unique_ptr<ObjectPropertiesResult> result = std::unique_ptr<ObjectPropertiesResult> result = GetHeapObjectProperties(
GetHeapObjectProperties(address, memory_accessor, roots, type_hint); address, memory_accessor, heap_addresses, type_hint);
if (is_weak) { if (is_weak) {
result->Prepend("weak ref to "); result->Prepend("weak ref to ");
} }
...@@ -520,9 +521,9 @@ extern "C" { ...@@ -520,9 +521,9 @@ extern "C" {
V8_DEBUG_HELPER_EXPORT d::ObjectPropertiesResult* V8_DEBUG_HELPER_EXPORT d::ObjectPropertiesResult*
_v8_debug_helper_GetObjectProperties(uintptr_t object, _v8_debug_helper_GetObjectProperties(uintptr_t object,
d::MemoryAccessor memory_accessor, d::MemoryAccessor memory_accessor,
const d::Roots& heap_roots, const d::HeapAddresses& heap_addresses,
const char* type_hint) { const char* type_hint) {
return di::GetObjectPropertiesImpl(object, memory_accessor, heap_roots, return di::GetObjectPropertiesImpl(object, memory_accessor, heap_addresses,
type_hint) type_hint)
.release() .release()
->GetPublicView(); ->GetPublicView();
......
...@@ -9,36 +9,37 @@ namespace d = v8::debug_helper; ...@@ -9,36 +9,37 @@ namespace d = v8::debug_helper;
namespace v8_debug_helper_internal { 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 containing_page = address & ~i::kPageAlignmentMask;
uintptr_t offset_in_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 there's a match with a known page, then search only that page.
if (containing_page == roots.map_space) { if (containing_page == heap_addresses.map_space_first_page) {
return FindKnownObjectInMapSpace(offset_in_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); 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); 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; std::string result;
if (roots.map_space == 0) { if (heap_addresses.map_space_first_page == 0) {
std::string sub_result = FindKnownObjectInMapSpace(offset_in_page); std::string sub_result = FindKnownObjectInMapSpace(offset_in_page);
if (!sub_result.empty()) { if (!sub_result.empty()) {
result += "maybe " + sub_result; 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); std::string sub_result = FindKnownObjectInOldSpace(offset_in_page);
if (!sub_result.empty()) { if (!sub_result.empty()) {
result = (result.empty() ? "" : result + ", ") + "maybe " + sub_result; 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); std::string sub_result = FindKnownObjectInReadOnlySpace(offset_in_page);
if (!sub_result.empty()) { if (!sub_result.empty()) {
result = (result.empty() ? "" : result + ", ") + "maybe " + sub_result; result = (result.empty() ? "" : result + ", ") + "maybe " + sub_result;
......
...@@ -14,14 +14,17 @@ namespace d = v8::debug_helper; ...@@ -14,14 +14,17 @@ namespace d = v8::debug_helper;
namespace v8_debug_helper_internal { 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 FindKnownObjectInOldSpace(uintptr_t offset);
std::string FindKnownObjectInReadOnlySpace(uintptr_t offset); std::string FindKnownObjectInReadOnlySpace(uintptr_t offset);
std::string FindKnownObjectInMapSpace(uintptr_t offset); std::string FindKnownObjectInMapSpace(uintptr_t offset);
std::string FindKnownMapInstanceTypeInMapSpace(uintptr_t offset); std::string FindKnownMapInstanceTypeInMapSpace(uintptr_t offset);
std::string FindKnownMapInstanceTypeInReadOnlySpace(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 } // namespace v8_debug_helper_internal
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment