2019-08-28 22:57:03 +00:00
|
|
|
|
// Copyright 2019 the V8 project authors. All rights reserved.
|
2019-03-11 21:00:20 +00:00
|
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
|
// found in the LICENSE file.
|
|
|
|
|
|
|
|
|
|
/*=============================================================================
|
|
|
|
|
This is a convenience script for debugging with WinDbg (akin to gdbinit)
|
|
|
|
|
It can be loaded into WinDbg with: .scriptload full_path\windbg.js
|
|
|
|
|
|
|
|
|
|
To printout the help message below into the debugger's command window:
|
|
|
|
|
!help
|
|
|
|
|
=============================================================================*/
|
|
|
|
|
|
|
|
|
|
function help() {
|
2019-08-28 22:57:03 +00:00
|
|
|
|
if (supports_call_command()) {
|
2019-03-11 21:00:20 +00:00
|
|
|
|
print("--------------------------------------------------------------------");
|
|
|
|
|
print(" LIVE debugging only");
|
|
|
|
|
print("--------------------------------------------------------------------");
|
|
|
|
|
print(" !jlh(\"local_handle_var_name\")");
|
|
|
|
|
print(" prints object held by the handle");
|
|
|
|
|
print(" e.g. !jlh(\"key\") or !jlh(\"this->receiver_\")");
|
|
|
|
|
print(" !job(address_or_taggedint)");
|
|
|
|
|
print(" prints object at the address, e.g. !job(0x235cb869f9)");
|
|
|
|
|
print(" !jobs(start_address, count)");
|
Added !mem and !where extensions to windbg.js
The extensions require isolate address to be set but don't rely on calling
any runtime functions, which makes them viable for post-mortem debugging,
if the corresponding memory is included into the dump
!set_iso(isolate_address)
call this function before using !mem or other heap routines
!mem or !mem(\"space1[ space2 ...]\")
prints memory chunks from the 'space' owned by the heap in the
isolate set by !set_iso; valid values for 'space' are:
new, old, map, code, lo [large], nlo [newlarge], ro [readonly]
if no 'space' specified prints memory chunks for all spaces,
e.g. !mem(\"code\"), !mem(\"ro new old\")
!where(address)
prints name of the space and address of the MemoryChunk the
'address' is from, e.g. !where(0x235cb869f9)
Output from !mem would look something like this:
0:000> !mem("old")
Heap at 0x210652b8838
Im address: object area start - end (size)
OldSpace (allocating at: 0x1703dae7a20):
* 0x33d9a8c0000: 0x33d9a8c0138 - 0x33d9a8f1000 (0x31000)
0x1703dac0000: 0x1703dac0138 - 0x1703db00000 (0x40000)
Change-Id: Iae1a217bbc5c5a88e2cf742db88ead9bb6fc904c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1669744
Commit-Queue: Irina Yatsenko <irinayat@microsoft.com>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Sergiy Belozorov <sergiyb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62316}
2019-06-21 15:22:03 +00:00
|
|
|
|
print(" prints 'count' objects from a continuous range of Object");
|
|
|
|
|
print(" pointers, e.g. !jobs(0x5f7270, 42)");
|
2019-03-11 21:00:20 +00:00
|
|
|
|
print(" !jst() or !jst");
|
|
|
|
|
print(" prints javascript stack (output goes into the console)");
|
|
|
|
|
print(" !jsbp() or !jsbp");
|
Added !mem and !where extensions to windbg.js
The extensions require isolate address to be set but don't rely on calling
any runtime functions, which makes them viable for post-mortem debugging,
if the corresponding memory is included into the dump
!set_iso(isolate_address)
call this function before using !mem or other heap routines
!mem or !mem(\"space1[ space2 ...]\")
prints memory chunks from the 'space' owned by the heap in the
isolate set by !set_iso; valid values for 'space' are:
new, old, map, code, lo [large], nlo [newlarge], ro [readonly]
if no 'space' specified prints memory chunks for all spaces,
e.g. !mem(\"code\"), !mem(\"ro new old\")
!where(address)
prints name of the space and address of the MemoryChunk the
'address' is from, e.g. !where(0x235cb869f9)
Output from !mem would look something like this:
0:000> !mem("old")
Heap at 0x210652b8838
Im address: object area start - end (size)
OldSpace (allocating at: 0x1703dae7a20):
* 0x33d9a8c0000: 0x33d9a8c0138 - 0x33d9a8f1000 (0x31000)
0x1703dac0000: 0x1703dac0138 - 0x1703db00000 (0x40000)
Change-Id: Iae1a217bbc5c5a88e2cf742db88ead9bb6fc904c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1669744
Commit-Queue: Irina Yatsenko <irinayat@microsoft.com>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Sergiy Belozorov <sergiyb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62316}
2019-06-21 15:22:03 +00:00
|
|
|
|
print(" sets bp in v8::internal::Execution::Call");
|
2019-03-11 21:00:20 +00:00
|
|
|
|
print("");
|
2019-08-28 22:57:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-03-11 21:00:20 +00:00
|
|
|
|
print("--------------------------------------------------------------------");
|
2019-08-28 22:57:03 +00:00
|
|
|
|
print(" Setup of the script");
|
Added !mem and !where extensions to windbg.js
The extensions require isolate address to be set but don't rely on calling
any runtime functions, which makes them viable for post-mortem debugging,
if the corresponding memory is included into the dump
!set_iso(isolate_address)
call this function before using !mem or other heap routines
!mem or !mem(\"space1[ space2 ...]\")
prints memory chunks from the 'space' owned by the heap in the
isolate set by !set_iso; valid values for 'space' are:
new, old, map, code, lo [large], nlo [newlarge], ro [readonly]
if no 'space' specified prints memory chunks for all spaces,
e.g. !mem(\"code\"), !mem(\"ro new old\")
!where(address)
prints name of the space and address of the MemoryChunk the
'address' is from, e.g. !where(0x235cb869f9)
Output from !mem would look something like this:
0:000> !mem("old")
Heap at 0x210652b8838
Im address: object area start - end (size)
OldSpace (allocating at: 0x1703dae7a20):
* 0x33d9a8c0000: 0x33d9a8c0138 - 0x33d9a8f1000 (0x31000)
0x1703dac0000: 0x1703dac0138 - 0x1703db00000 (0x40000)
Change-Id: Iae1a217bbc5c5a88e2cf742db88ead9bb6fc904c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1669744
Commit-Queue: Irina Yatsenko <irinayat@microsoft.com>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Sergiy Belozorov <sergiyb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62316}
2019-06-21 15:22:03 +00:00
|
|
|
|
print("--------------------------------------------------------------------");
|
2019-08-28 22:57:03 +00:00
|
|
|
|
print(" !set_module(\"module_name_no_extension\")");
|
|
|
|
|
print(" we'll try the usual suspects for where v8's code might have");
|
|
|
|
|
print(" been linked into, but you can also set it manually,");
|
|
|
|
|
print(" e.g. !set_module(\"v8_for_testing\")");
|
Added !mem and !where extensions to windbg.js
The extensions require isolate address to be set but don't rely on calling
any runtime functions, which makes them viable for post-mortem debugging,
if the corresponding memory is included into the dump
!set_iso(isolate_address)
call this function before using !mem or other heap routines
!mem or !mem(\"space1[ space2 ...]\")
prints memory chunks from the 'space' owned by the heap in the
isolate set by !set_iso; valid values for 'space' are:
new, old, map, code, lo [large], nlo [newlarge], ro [readonly]
if no 'space' specified prints memory chunks for all spaces,
e.g. !mem(\"code\"), !mem(\"ro new old\")
!where(address)
prints name of the space and address of the MemoryChunk the
'address' is from, e.g. !where(0x235cb869f9)
Output from !mem would look something like this:
0:000> !mem("old")
Heap at 0x210652b8838
Im address: object area start - end (size)
OldSpace (allocating at: 0x1703dae7a20):
* 0x33d9a8c0000: 0x33d9a8c0138 - 0x33d9a8f1000 (0x31000)
0x1703dac0000: 0x1703dac0138 - 0x1703db00000 (0x40000)
Change-Id: Iae1a217bbc5c5a88e2cf742db88ead9bb6fc904c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1669744
Commit-Queue: Irina Yatsenko <irinayat@microsoft.com>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Sergiy Belozorov <sergiyb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62316}
2019-06-21 15:22:03 +00:00
|
|
|
|
print(" !set_iso(isolate_address)");
|
|
|
|
|
print(" call this function before using !mem or other heap routines");
|
2019-08-28 22:57:03 +00:00
|
|
|
|
print("");
|
|
|
|
|
|
|
|
|
|
print("--------------------------------------------------------------------");
|
|
|
|
|
print(" Managed heap");
|
|
|
|
|
print("--------------------------------------------------------------------");
|
Added !mem and !where extensions to windbg.js
The extensions require isolate address to be set but don't rely on calling
any runtime functions, which makes them viable for post-mortem debugging,
if the corresponding memory is included into the dump
!set_iso(isolate_address)
call this function before using !mem or other heap routines
!mem or !mem(\"space1[ space2 ...]\")
prints memory chunks from the 'space' owned by the heap in the
isolate set by !set_iso; valid values for 'space' are:
new, old, map, code, lo [large], nlo [newlarge], ro [readonly]
if no 'space' specified prints memory chunks for all spaces,
e.g. !mem(\"code\"), !mem(\"ro new old\")
!where(address)
prints name of the space and address of the MemoryChunk the
'address' is from, e.g. !where(0x235cb869f9)
Output from !mem would look something like this:
0:000> !mem("old")
Heap at 0x210652b8838
Im address: object area start - end (size)
OldSpace (allocating at: 0x1703dae7a20):
* 0x33d9a8c0000: 0x33d9a8c0138 - 0x33d9a8f1000 (0x31000)
0x1703dac0000: 0x1703dac0138 - 0x1703db00000 (0x40000)
Change-Id: Iae1a217bbc5c5a88e2cf742db88ead9bb6fc904c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1669744
Commit-Queue: Irina Yatsenko <irinayat@microsoft.com>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Sergiy Belozorov <sergiyb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62316}
2019-06-21 15:22:03 +00:00
|
|
|
|
print(" !mem or !mem(\"space1[ space2 ...]\")");
|
|
|
|
|
print(" prints memory chunks from the 'space' owned by the heap in the");
|
|
|
|
|
print(" isolate set by !set_iso; valid values for 'space' are:");
|
|
|
|
|
print(" new, old, map, code, lo [large], nlo [newlarge], ro [readonly]");
|
|
|
|
|
print(" if no 'space' specified prints memory chunks for all spaces,");
|
|
|
|
|
print(" e.g. !mem(\"code\"), !mem(\"ro new old\")");
|
|
|
|
|
print(" !where(address)");
|
|
|
|
|
print(" prints name of the space and address of the MemoryChunk the");
|
|
|
|
|
print(" 'address' is from, e.g. !where(0x235cb869f9)");
|
|
|
|
|
print("");
|
2019-08-28 22:57:03 +00:00
|
|
|
|
|
|
|
|
|
print("--------------------------------------------------------------------");
|
|
|
|
|
print(" Managed objects");
|
|
|
|
|
print("--------------------------------------------------------------------");
|
|
|
|
|
print(" !jot(tagged_addr, depth)");
|
|
|
|
|
print(" dumps the tree of objects using 'tagged_addr' as a root,");
|
|
|
|
|
print(" assumes that pointer fields are aligned at ptr_size boundary,");
|
|
|
|
|
print(" unspecified depth means 'unlimited',");
|
|
|
|
|
print(" e.g. !jot(0x235cb869f9, 2), !jot 0x235cb869f9");
|
|
|
|
|
print(" !jo_in_range(start_addr, end_addr)");
|
|
|
|
|
print(" prints address/map pointers of objects found inside the range");
|
|
|
|
|
print(" specified by 'start_addr' and 'end_addr', assumes the object");
|
|
|
|
|
print(" pointers to be aligned at ptr_size boundary,");
|
|
|
|
|
print(" e.g. !jo_in_range(0x235cb869f8 - 0x100, 0x235cb869f8 + 0x1a0");
|
|
|
|
|
print(" !jo_prev(address, max_slots = 100)");
|
|
|
|
|
print(" prints address and map pointer of the nearest object within");
|
|
|
|
|
print(" 'max_slots' before the given 'address', assumes the object");
|
|
|
|
|
print(" pointers to be aligned at ptr_size boundary,");
|
|
|
|
|
print(" e.g. !jo_prev 0x235cb869f8, !jo_prev(0x235cb869f9, 16)");
|
|
|
|
|
print(" !jo_next(address, max_slots = 100)");
|
|
|
|
|
print(" prints address and map pointer of the nearest object within");
|
|
|
|
|
print(" 'max_slots' following the given 'address', assumes the object");
|
|
|
|
|
print(" pointers to be aligned at ptr_size boundary,");
|
|
|
|
|
print(" e.g. !jo_next 0x235cb869f8, !jo_next(0x235cb869f9, 20)");
|
|
|
|
|
print("");
|
|
|
|
|
|
|
|
|
|
print("--------------------------------------------------------------------");
|
|
|
|
|
print(" Miscellaneous");
|
|
|
|
|
print("--------------------------------------------------------------------");
|
|
|
|
|
print(" !dp(address, count = 10)");
|
|
|
|
|
print(" similar to the built-in 'dp' command but augments output with");
|
|
|
|
|
print(" more data for values that are managed pointers, note that it");
|
|
|
|
|
print(" aligns the given 'address' at ptr_sized boundary,");
|
|
|
|
|
print(" e.g. !dp 0x235cb869f9, !dp(0x235cb869f9, 500), !dp @rsp");
|
|
|
|
|
print(" !handles(print_handles = false)");
|
|
|
|
|
print(" prints stats for handles, if 'print_handles' is true will");
|
|
|
|
|
print(" output all handles as well,");
|
|
|
|
|
print(" e.g. !handles, !handles(), !handles(true)");
|
|
|
|
|
print("");
|
|
|
|
|
|
Added !mem and !where extensions to windbg.js
The extensions require isolate address to be set but don't rely on calling
any runtime functions, which makes them viable for post-mortem debugging,
if the corresponding memory is included into the dump
!set_iso(isolate_address)
call this function before using !mem or other heap routines
!mem or !mem(\"space1[ space2 ...]\")
prints memory chunks from the 'space' owned by the heap in the
isolate set by !set_iso; valid values for 'space' are:
new, old, map, code, lo [large], nlo [newlarge], ro [readonly]
if no 'space' specified prints memory chunks for all spaces,
e.g. !mem(\"code\"), !mem(\"ro new old\")
!where(address)
prints name of the space and address of the MemoryChunk the
'address' is from, e.g. !where(0x235cb869f9)
Output from !mem would look something like this:
0:000> !mem("old")
Heap at 0x210652b8838
Im address: object area start - end (size)
OldSpace (allocating at: 0x1703dae7a20):
* 0x33d9a8c0000: 0x33d9a8c0138 - 0x33d9a8f1000 (0x31000)
0x1703dac0000: 0x1703dac0138 - 0x1703db00000 (0x40000)
Change-Id: Iae1a217bbc5c5a88e2cf742db88ead9bb6fc904c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1669744
Commit-Queue: Irina Yatsenko <irinayat@microsoft.com>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Sergiy Belozorov <sergiyb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62316}
2019-06-21 15:22:03 +00:00
|
|
|
|
print("--------------------------------------------------------------------");
|
|
|
|
|
print(" To run any function from this script (live or postmortem):");
|
2019-03-11 21:00:20 +00:00
|
|
|
|
print("");
|
|
|
|
|
print(" dx @$scriptContents.function_name(args)");
|
|
|
|
|
print(" e.g. dx @$scriptContents.pointer_size()");
|
2019-08-28 22:57:03 +00:00
|
|
|
|
print(" e.g. dx @$scriptContents.is_map(0x235cb869f9)");
|
2019-03-11 21:00:20 +00:00
|
|
|
|
print("--------------------------------------------------------------------");
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-28 22:57:03 +00:00
|
|
|
|
/*=============================================================================
|
|
|
|
|
On scrip load
|
|
|
|
|
=============================================================================*/
|
|
|
|
|
|
2019-03-11 21:00:20 +00:00
|
|
|
|
/*=============================================================================
|
|
|
|
|
Output
|
|
|
|
|
=============================================================================*/
|
|
|
|
|
function print(s) {
|
|
|
|
|
host.diagnostics.debugLog(s + "\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function print_filtered(obj, filter) {
|
|
|
|
|
for (let line of obj) {
|
|
|
|
|
if (!filter || line.indexOf(filter) != -1) {
|
|
|
|
|
print(line);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function inspect(s) {
|
2019-08-28 22:57:03 +00:00
|
|
|
|
for (let k of Reflect.ownKeys(s)) {
|
|
|
|
|
// Attempting to print either of:
|
|
|
|
|
// 'Reflect.get(s, k)', 'typeof Reflect.get(s, k)', 's[k]'
|
|
|
|
|
// might throw: "Error: Object does not have a size",
|
|
|
|
|
// while 'typeof s[k]' returns 'undefined' and prints the full list of
|
|
|
|
|
// properties. Oh well...
|
|
|
|
|
print(`${k} => ${typeof s[k]}`);
|
2019-03-11 21:00:20 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-28 22:57:03 +00:00
|
|
|
|
function hex(number) {
|
|
|
|
|
return `0x${number.toString(16)}`;
|
|
|
|
|
}
|
2019-03-11 21:00:20 +00:00
|
|
|
|
|
|
|
|
|
/*=============================================================================
|
|
|
|
|
Utils (postmortem and live)
|
|
|
|
|
=============================================================================*/
|
2019-08-28 22:57:03 +00:00
|
|
|
|
// WinDbg wraps large integers into objects that fail isInteger test (and,
|
|
|
|
|
// consequently fail isSafeInteger test even if the original value was a safe
|
|
|
|
|
// integer). I cannot figure out how to extract the original value from the
|
|
|
|
|
// wrapper object so doing it via conversion to a string. Brrr. Ugly.
|
|
|
|
|
function int(val) {
|
|
|
|
|
if (typeof val === 'number') {
|
|
|
|
|
return Number.isInteger(val) ? val : undefined;
|
|
|
|
|
}
|
|
|
|
|
if (typeof val === 'object') {
|
|
|
|
|
let n = parseInt(val.toString());
|
|
|
|
|
return isNaN(n) ? undefined : n;
|
|
|
|
|
}
|
|
|
|
|
return undefined;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function is_live_session() {
|
|
|
|
|
// Assume that there is a single session (not sure how to get multiple ones
|
|
|
|
|
// going, maybe, in kernel debugging?).
|
|
|
|
|
return (host.namespace.Debugger.Sessions[0].Attributes.Target.IsLiveTarget);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function is_TTD_session() {
|
|
|
|
|
// Assume that there is a single session (not sure how to get multiple ones
|
|
|
|
|
// going, maybe, in kernel debugging?).
|
|
|
|
|
return (host.namespace.Debugger.Sessions[0].Attributes.Target.IsTTDTarget);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function supports_call_command() {
|
|
|
|
|
return is_live_session() && !is_TTD_session();
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-11 21:00:20 +00:00
|
|
|
|
function cast(address, type_name) {
|
|
|
|
|
return host.createTypedObject(address, module_name(), type_name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function pointer_size() {
|
2019-08-28 22:57:03 +00:00
|
|
|
|
return host.namespace.Debugger.Sessions[0].Attributes.Machine.PointerSize;
|
2019-03-11 21:00:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function poi(address) {
|
|
|
|
|
try {
|
|
|
|
|
// readMemoryValues throws if cannot read from 'address'.
|
|
|
|
|
return host.memory.readMemoryValues(address, 1, pointer_size())[0];
|
|
|
|
|
}
|
|
|
|
|
catch (e){}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function get_register(name) {
|
|
|
|
|
return host.namespace.Debugger.State.DebuggerVariables.curthread
|
|
|
|
|
.Registers.User[name];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// In debug builds v8 code is compiled into v8.dll, and in release builds
|
|
|
|
|
// the code is compiled directly into the executable. If you are debugging some
|
2019-08-28 22:57:03 +00:00
|
|
|
|
// other embedder, run !set_module and provide the module name to use.
|
2019-03-11 21:00:20 +00:00
|
|
|
|
const known_exes = ["d8", "unittests", "mksnapshot", "chrome", "chromium"];
|
|
|
|
|
let module_name_cache;
|
|
|
|
|
function module_name(use_this_module) {
|
|
|
|
|
if (use_this_module) {
|
|
|
|
|
module_name_cache = use_this_module;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!module_name_cache) {
|
|
|
|
|
let v8 = host.namespace.Debugger.State.DebuggerVariables.curprocess
|
|
|
|
|
.Modules.Where(
|
|
|
|
|
function(m) {
|
|
|
|
|
return m.Name.indexOf("\\v8.dll") !== -1;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (v8) {
|
|
|
|
|
module_name_cache = "v8";
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
for (let exe_name in known_exes) {
|
|
|
|
|
let exe = host.namespace.Debugger.State.DebuggerVariables.curprocess
|
|
|
|
|
.Modules.Where(
|
|
|
|
|
function(m) {
|
|
|
|
|
return m.Name.indexOf(`\\${exe_name}.exe`) !== -1;
|
|
|
|
|
});
|
|
|
|
|
if (exe) {
|
|
|
|
|
module_name_cache = exe_name;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-08-28 22:57:03 +00:00
|
|
|
|
|
|
|
|
|
if (!module_name_cache) {
|
|
|
|
|
print(`ERROR. Couldn't determine module name for v8's symbols.`);
|
|
|
|
|
print(`Please run !set_module (e.g. "!set_module \"v8_for_testing\"")`);
|
|
|
|
|
}
|
2019-03-11 21:00:20 +00:00
|
|
|
|
return module_name_cache;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
function make_call(fn) {
|
2019-08-28 22:57:03 +00:00
|
|
|
|
if (!supports_call_command()) {
|
|
|
|
|
print("ERROR: This command is supported in live sessions only!");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-11 21:00:20 +00:00
|
|
|
|
// .call resets current frame to the top one, so have to manually remember
|
|
|
|
|
// and restore it after making the call.
|
|
|
|
|
let curframe = host.namespace.Debugger.State.DebuggerVariables.curframe;
|
|
|
|
|
let ctl = host.namespace.Debugger.Utility.Control;
|
|
|
|
|
let output = ctl.ExecuteCommand(`.call ${fn};g`);
|
|
|
|
|
curframe.SwitchTo();
|
|
|
|
|
return output;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*=============================================================================
|
|
|
|
|
Wrappers around V8's printing functions and other utils for live-debugging
|
|
|
|
|
=============================================================================*/
|
|
|
|
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
|
'address' should be an int (so in hex must include '0x' prefix).
|
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
|
function print_object(address) {
|
|
|
|
|
let output = make_call(`_v8_internal_Print_Object(${address})`);
|
|
|
|
|
|
|
|
|
|
// skip the first few lines with meta info of .call command
|
|
|
|
|
let skip_line = true;
|
|
|
|
|
for (let line of output) {
|
|
|
|
|
if (!skip_line) {
|
|
|
|
|
print(line);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (line.includes("deadlocks and corruption of the debuggee")) {
|
|
|
|
|
skip_line = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
|
'handle_to_object' should be a name of a Handle which can be a local
|
|
|
|
|
variable or it can be a member variable like "this->receiver_".
|
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
|
function print_object_from_handle(handle_to_object) {
|
|
|
|
|
let handle = host.evaluateExpression(handle_to_object);
|
|
|
|
|
let location = handle.location_;
|
|
|
|
|
let pobj = poi(location.address);
|
|
|
|
|
print_object(pobj);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
|
'start_address' should be an int (so in hex must include '0x' prefix), it can
|
|
|
|
|
point at any continuous memory that contains Object pointers.
|
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
|
function print_objects_array(start_address, count) {
|
2019-08-28 22:57:03 +00:00
|
|
|
|
const ptr_size = pointer_size();
|
2019-03-11 21:00:20 +00:00
|
|
|
|
let ctl = host.namespace.Debugger.Utility.Control;
|
|
|
|
|
let addr_int = start_address;
|
|
|
|
|
for (let i = 0; i < count; i++) {
|
2019-08-28 22:57:03 +00:00
|
|
|
|
const addr_hex = hex(addr_int);
|
2019-03-11 21:00:20 +00:00
|
|
|
|
|
|
|
|
|
// TODO: Tried using createPointerObject but it throws unknown exception
|
|
|
|
|
// from ChakraCore. Why?
|
|
|
|
|
//let obj = host.createPointerObject(addr_hex, module, "void*");
|
|
|
|
|
|
|
|
|
|
let output = ctl.ExecuteCommand(`dp ${addr_hex} l1`);
|
|
|
|
|
let item = "";
|
|
|
|
|
for (item of output) {} // 005f7270 34604101
|
|
|
|
|
let deref = `0x${item.split(" ").pop()}`;
|
|
|
|
|
print(`${addr_hex} -> ${deref}`);
|
|
|
|
|
print_object(deref);
|
|
|
|
|
|
2019-08-28 22:57:03 +00:00
|
|
|
|
addr_int += ptr_size;
|
2019-03-11 21:00:20 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function print_js_stack() {
|
|
|
|
|
make_call("_v8_internal_Print_StackTrace()");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function set_user_js_bp() {
|
|
|
|
|
let ctl = host.namespace.Debugger.Utility.Control;
|
|
|
|
|
ctl.ExecuteCommand(`bp ${module_name()}!v8::internal::Execution::Call`)
|
|
|
|
|
}
|
|
|
|
|
|
Added !mem and !where extensions to windbg.js
The extensions require isolate address to be set but don't rely on calling
any runtime functions, which makes them viable for post-mortem debugging,
if the corresponding memory is included into the dump
!set_iso(isolate_address)
call this function before using !mem or other heap routines
!mem or !mem(\"space1[ space2 ...]\")
prints memory chunks from the 'space' owned by the heap in the
isolate set by !set_iso; valid values for 'space' are:
new, old, map, code, lo [large], nlo [newlarge], ro [readonly]
if no 'space' specified prints memory chunks for all spaces,
e.g. !mem(\"code\"), !mem(\"ro new old\")
!where(address)
prints name of the space and address of the MemoryChunk the
'address' is from, e.g. !where(0x235cb869f9)
Output from !mem would look something like this:
0:000> !mem("old")
Heap at 0x210652b8838
Im address: object area start - end (size)
OldSpace (allocating at: 0x1703dae7a20):
* 0x33d9a8c0000: 0x33d9a8c0138 - 0x33d9a8f1000 (0x31000)
0x1703dac0000: 0x1703dac0138 - 0x1703db00000 (0x40000)
Change-Id: Iae1a217bbc5c5a88e2cf742db88ead9bb6fc904c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1669744
Commit-Queue: Irina Yatsenko <irinayat@microsoft.com>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Sergiy Belozorov <sergiyb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62316}
2019-06-21 15:22:03 +00:00
|
|
|
|
|
|
|
|
|
/*=============================================================================
|
|
|
|
|
Managed heap related functions (live and post-mortem debugging)
|
|
|
|
|
=============================================================================*/
|
|
|
|
|
let isolate_address = 0;
|
|
|
|
|
function set_isolate_address(addr) {
|
|
|
|
|
isolate_address = addr;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-28 22:57:03 +00:00
|
|
|
|
function is_map(addr) {
|
|
|
|
|
let address = int(addr);
|
|
|
|
|
if (!Number.isSafeInteger(address) || address % 2 == 0) return false;
|
|
|
|
|
|
|
|
|
|
// the first field in all objects, including maps, is a map pointer, but for
|
|
|
|
|
// maps the pointer is always the same - the meta map that points to itself.
|
|
|
|
|
const map_addr = int(poi(address - 1));
|
|
|
|
|
if (!Number.isSafeInteger(map_addr)) return false;
|
|
|
|
|
|
|
|
|
|
const map_map_addr = int(poi(map_addr - 1));
|
|
|
|
|
if (!Number.isSafeInteger(map_map_addr)) return false;
|
|
|
|
|
|
|
|
|
|
return (map_addr === map_map_addr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function is_likely_object(addr) {
|
|
|
|
|
let address = int(addr);
|
|
|
|
|
if (!Number.isSafeInteger(address) || address % 2 == 0) return false;
|
|
|
|
|
|
|
|
|
|
// the first field in all objects must be a map pointer
|
|
|
|
|
return is_map(poi(address - 1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function find_object_near(aligned_addr, max_distance, step_op) {
|
|
|
|
|
if (!step_op) {
|
|
|
|
|
const step = pointer_size();
|
|
|
|
|
const prev =
|
|
|
|
|
find_object_near(aligned_addr, max_distance, x => x - step);
|
|
|
|
|
const next =
|
|
|
|
|
find_object_near(aligned_addr, max_distance, x => x + step);
|
|
|
|
|
|
|
|
|
|
if (!prev) return next;
|
|
|
|
|
if (!next) return prev;
|
|
|
|
|
return (addr - prev <= next - addr) ? prev : next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let maybe_map_addr = poi(aligned_addr);
|
|
|
|
|
let iters = 0;
|
|
|
|
|
while (maybe_map_addr && iters < max_distance) {
|
|
|
|
|
if (is_map(maybe_map_addr)) {
|
|
|
|
|
return aligned_addr;
|
|
|
|
|
}
|
|
|
|
|
aligned_addr = step_op(aligned_addr);
|
|
|
|
|
maybe_map_addr = poi(aligned_addr);
|
|
|
|
|
iters++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function find_object_prev(addr, max_distance) {
|
|
|
|
|
if (!Number.isSafeInteger(int(addr))) return;
|
|
|
|
|
|
|
|
|
|
const ptr_size = pointer_size();
|
|
|
|
|
const aligned_addr = addr - (addr % ptr_size);
|
|
|
|
|
return find_object_near(aligned_addr, max_distance, x => x - ptr_size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function find_object_next(addr, max_distance) {
|
|
|
|
|
if (!Number.isSafeInteger(int(addr))) return;
|
|
|
|
|
|
|
|
|
|
const ptr_size = pointer_size();
|
|
|
|
|
const aligned_addr = addr - (addr % ptr_size) + ptr_size;
|
|
|
|
|
return find_object_near(aligned_addr, max_distance, x => x + ptr_size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function print_object_prev(addr, max_slots = 100) {
|
|
|
|
|
let obj_addr = find_object_prev(addr, max_slots);
|
|
|
|
|
if (!obj_addr) {
|
|
|
|
|
print(
|
|
|
|
|
`No object found within ${max_slots} slots prior to ${hex(addr)}`);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
print(
|
|
|
|
|
`found object: ${hex(obj_addr + 1)} : ${hex(poi(obj_addr))}`);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function print_object_next(addr, max_slots = 100) {
|
|
|
|
|
let obj_addr = find_object_next(addr, max_slots);
|
|
|
|
|
if (!obj_addr) {
|
|
|
|
|
print(
|
|
|
|
|
`No object found within ${max_slots} slots following ${hex(addr)}`);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
print(
|
|
|
|
|
`found object: ${hex(obj_addr + 1)} : ${hex(poi(obj_addr))}`);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This function assumes that pointers to objects are stored at ptr-size aligned
|
|
|
|
|
// boundaries.
|
|
|
|
|
function print_objects_in_range(start, end){
|
|
|
|
|
if (!Number.isSafeInteger(int(start)) || !Number.isSafeInteger(int(end))) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const ptr_size = pointer_size();
|
|
|
|
|
let iters = (end - start) / ptr_size;
|
|
|
|
|
let cur = start;
|
|
|
|
|
print(`===============================================`);
|
|
|
|
|
print(`objects in range ${hex(start)} - ${hex(end)}`);
|
|
|
|
|
print(`===============================================`);
|
|
|
|
|
let count = 0;
|
|
|
|
|
while (cur && cur < end) {
|
|
|
|
|
let obj = find_object_next(cur, iters);
|
|
|
|
|
if (obj) {
|
|
|
|
|
count++;
|
|
|
|
|
print(`${hex(obj + 1)} : ${hex(poi(obj))}`);
|
|
|
|
|
iters = (end - cur) / ptr_size;
|
|
|
|
|
}
|
|
|
|
|
cur = obj + ptr_size;
|
|
|
|
|
}
|
|
|
|
|
print(`===============================================`);
|
|
|
|
|
print(`found ${count} objects in range ${hex(start)} - ${hex(end)}`)
|
|
|
|
|
print(`===============================================`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This function assumes the pointer fields to be ptr-size aligned.
|
|
|
|
|
function print_objects_tree(root, depth_limit) {
|
|
|
|
|
if(!is_likely_object(root)) {
|
|
|
|
|
print(`${hex(root)} doesn't look like an object`);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let path = [];
|
|
|
|
|
|
|
|
|
|
function impl(obj, depth, depth_limit) {
|
|
|
|
|
const ptr_size = pointer_size();
|
|
|
|
|
// print the current object and its map pointer
|
|
|
|
|
const this_obj =
|
|
|
|
|
`${" ".repeat(2 * depth)}${hex(obj)} : ${hex(poi(obj - 1))}`;
|
|
|
|
|
const cutoff = depth_limit && depth == depth_limit - 1;
|
|
|
|
|
print(`${this_obj}${cutoff ? " (...)" : ""}`);
|
|
|
|
|
if (cutoff) return;
|
|
|
|
|
|
|
|
|
|
path[depth] = obj;
|
|
|
|
|
path.length = depth + 1;
|
|
|
|
|
let cur = obj - 1 + ptr_size;
|
|
|
|
|
|
|
|
|
|
// Scan downwards until an address that is likely to be at the start of
|
|
|
|
|
// another object, in which case it's time to pop out from the recursion.
|
|
|
|
|
let iter = 0; // an arbitrary guard to avoid hanging the debugger
|
|
|
|
|
let seen = new Set(path);
|
|
|
|
|
while (!is_likely_object(cur + 1) && iter < 100) {
|
|
|
|
|
iter++;
|
|
|
|
|
let field = poi(cur);
|
|
|
|
|
if (is_likely_object(field)) {
|
|
|
|
|
if (seen.has(field)) {
|
|
|
|
|
print(
|
|
|
|
|
`${" ".repeat(2 * depth + 2)}cycle: ${hex(cur)}->${hex(field)}`);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
impl(field, depth + 1, depth_limit);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
cur += ptr_size;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
print(`===============================================`);
|
|
|
|
|
impl(root, 0, depth_limit);
|
|
|
|
|
print(`===============================================`);
|
|
|
|
|
}
|
|
|
|
|
|
Added !mem and !where extensions to windbg.js
The extensions require isolate address to be set but don't rely on calling
any runtime functions, which makes them viable for post-mortem debugging,
if the corresponding memory is included into the dump
!set_iso(isolate_address)
call this function before using !mem or other heap routines
!mem or !mem(\"space1[ space2 ...]\")
prints memory chunks from the 'space' owned by the heap in the
isolate set by !set_iso; valid values for 'space' are:
new, old, map, code, lo [large], nlo [newlarge], ro [readonly]
if no 'space' specified prints memory chunks for all spaces,
e.g. !mem(\"code\"), !mem(\"ro new old\")
!where(address)
prints name of the space and address of the MemoryChunk the
'address' is from, e.g. !where(0x235cb869f9)
Output from !mem would look something like this:
0:000> !mem("old")
Heap at 0x210652b8838
Im address: object area start - end (size)
OldSpace (allocating at: 0x1703dae7a20):
* 0x33d9a8c0000: 0x33d9a8c0138 - 0x33d9a8f1000 (0x31000)
0x1703dac0000: 0x1703dac0138 - 0x1703db00000 (0x40000)
Change-Id: Iae1a217bbc5c5a88e2cf742db88ead9bb6fc904c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1669744
Commit-Queue: Irina Yatsenko <irinayat@microsoft.com>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Sergiy Belozorov <sergiyb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62316}
2019-06-21 15:22:03 +00:00
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
|
Memory in each Space is organized into a linked list of memory chunks
|
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
|
const NEVER_EVACUATE = 1 << 7; // see src\heap\spaces.h
|
|
|
|
|
|
|
|
|
|
function print_memory_chunk_list(space_type, front, top, age_mark) {
|
|
|
|
|
let alloc_pos = top ? ` (allocating at: ${top})` : "";
|
|
|
|
|
let age_mark_pos = age_mark ? ` (age_mark at: ${top})` : "";
|
|
|
|
|
print(`${space_type}${alloc_pos}${age_mark_pos}:`);
|
|
|
|
|
if (front.isNull) {
|
|
|
|
|
print("<empty>\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let cur = front;
|
|
|
|
|
while (!cur.isNull) {
|
|
|
|
|
let imm = cur.flags_ & NEVER_EVACUATE ? "*" : " ";
|
2019-08-28 22:57:03 +00:00
|
|
|
|
let addr = hex(cur.address);
|
|
|
|
|
let area = `${hex(cur.area_start_)} - ${hex(cur.area_end_)}`;
|
Added !mem and !where extensions to windbg.js
The extensions require isolate address to be set but don't rely on calling
any runtime functions, which makes them viable for post-mortem debugging,
if the corresponding memory is included into the dump
!set_iso(isolate_address)
call this function before using !mem or other heap routines
!mem or !mem(\"space1[ space2 ...]\")
prints memory chunks from the 'space' owned by the heap in the
isolate set by !set_iso; valid values for 'space' are:
new, old, map, code, lo [large], nlo [newlarge], ro [readonly]
if no 'space' specified prints memory chunks for all spaces,
e.g. !mem(\"code\"), !mem(\"ro new old\")
!where(address)
prints name of the space and address of the MemoryChunk the
'address' is from, e.g. !where(0x235cb869f9)
Output from !mem would look something like this:
0:000> !mem("old")
Heap at 0x210652b8838
Im address: object area start - end (size)
OldSpace (allocating at: 0x1703dae7a20):
* 0x33d9a8c0000: 0x33d9a8c0138 - 0x33d9a8f1000 (0x31000)
0x1703dac0000: 0x1703dac0138 - 0x1703db00000 (0x40000)
Change-Id: Iae1a217bbc5c5a88e2cf742db88ead9bb6fc904c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1669744
Commit-Queue: Irina Yatsenko <irinayat@microsoft.com>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Sergiy Belozorov <sergiyb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62316}
2019-06-21 15:22:03 +00:00
|
|
|
|
let dt = `dt ${addr} ${module_name()}!v8::internal::MemoryChunk`;
|
2019-08-28 22:57:03 +00:00
|
|
|
|
print(`${imm} ${addr}:\t ${area} (${hex(cur.size_)}) : ${dt}`);
|
Added !mem and !where extensions to windbg.js
The extensions require isolate address to be set but don't rely on calling
any runtime functions, which makes them viable for post-mortem debugging,
if the corresponding memory is included into the dump
!set_iso(isolate_address)
call this function before using !mem or other heap routines
!mem or !mem(\"space1[ space2 ...]\")
prints memory chunks from the 'space' owned by the heap in the
isolate set by !set_iso; valid values for 'space' are:
new, old, map, code, lo [large], nlo [newlarge], ro [readonly]
if no 'space' specified prints memory chunks for all spaces,
e.g. !mem(\"code\"), !mem(\"ro new old\")
!where(address)
prints name of the space and address of the MemoryChunk the
'address' is from, e.g. !where(0x235cb869f9)
Output from !mem would look something like this:
0:000> !mem("old")
Heap at 0x210652b8838
Im address: object area start - end (size)
OldSpace (allocating at: 0x1703dae7a20):
* 0x33d9a8c0000: 0x33d9a8c0138 - 0x33d9a8f1000 (0x31000)
0x1703dac0000: 0x1703dac0138 - 0x1703db00000 (0x40000)
Change-Id: Iae1a217bbc5c5a88e2cf742db88ead9bb6fc904c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1669744
Commit-Queue: Irina Yatsenko <irinayat@microsoft.com>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Sergiy Belozorov <sergiyb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62316}
2019-06-21 15:22:03 +00:00
|
|
|
|
cur = cur.list_node_.next_;
|
|
|
|
|
}
|
|
|
|
|
print("");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const space_tags =
|
|
|
|
|
['old', 'new_to', 'new_from', 'ro', 'map', 'code', 'lo', 'nlo'];
|
|
|
|
|
|
|
|
|
|
function get_chunks_space(space_tag, front, chunks) {
|
|
|
|
|
let cur = front;
|
|
|
|
|
while (!cur.isNull) {
|
|
|
|
|
chunks.push({
|
|
|
|
|
'address':cur.address,
|
|
|
|
|
'area_start_':cur.area_start_,
|
|
|
|
|
'area_end_':cur.area_end_,
|
|
|
|
|
'space':space_tag});
|
|
|
|
|
cur = cur.list_node_.next_;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function get_chunks() {
|
|
|
|
|
let iso = cast(isolate_address, "v8::internal::Isolate");
|
|
|
|
|
let h = iso.heap_;
|
|
|
|
|
|
|
|
|
|
let chunks = [];
|
|
|
|
|
get_chunks_space('old', h.old_space_.memory_chunk_list_.front_, chunks);
|
|
|
|
|
get_chunks_space('new_to',
|
|
|
|
|
h.new_space_.to_space_.memory_chunk_list_.front_, chunks);
|
|
|
|
|
get_chunks_space('new_from',
|
|
|
|
|
h.new_space_.from_space_.memory_chunk_list_.front_, chunks);
|
|
|
|
|
get_chunks_space('ro', h.read_only_space_.memory_chunk_list_.front_, chunks);
|
|
|
|
|
get_chunks_space('map', h.map_space_.memory_chunk_list_.front_, chunks);
|
|
|
|
|
get_chunks_space('code', h.code_space_.memory_chunk_list_.front_, chunks);
|
|
|
|
|
get_chunks_space('lo', h.lo_space_.memory_chunk_list_.front_, chunks);
|
|
|
|
|
get_chunks_space('nlo', h.new_lo_space_.memory_chunk_list_.front_, chunks);
|
|
|
|
|
|
|
|
|
|
return chunks;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function find_chunk(address) {
|
2019-08-28 22:57:03 +00:00
|
|
|
|
if (!Number.isSafeInteger(int(address))) return undefined;
|
|
|
|
|
|
|
|
|
|
let chunks = get_chunks(isolate_address);
|
|
|
|
|
for (let c of chunks) {
|
|
|
|
|
let chunk = cast(c.address, "v8::internal::MemoryChunk");
|
|
|
|
|
if (address >= chunk.area_start_ && address < chunk.area_end_) {
|
|
|
|
|
return c;
|
Added !mem and !where extensions to windbg.js
The extensions require isolate address to be set but don't rely on calling
any runtime functions, which makes them viable for post-mortem debugging,
if the corresponding memory is included into the dump
!set_iso(isolate_address)
call this function before using !mem or other heap routines
!mem or !mem(\"space1[ space2 ...]\")
prints memory chunks from the 'space' owned by the heap in the
isolate set by !set_iso; valid values for 'space' are:
new, old, map, code, lo [large], nlo [newlarge], ro [readonly]
if no 'space' specified prints memory chunks for all spaces,
e.g. !mem(\"code\"), !mem(\"ro new old\")
!where(address)
prints name of the space and address of the MemoryChunk the
'address' is from, e.g. !where(0x235cb869f9)
Output from !mem would look something like this:
0:000> !mem("old")
Heap at 0x210652b8838
Im address: object area start - end (size)
OldSpace (allocating at: 0x1703dae7a20):
* 0x33d9a8c0000: 0x33d9a8c0138 - 0x33d9a8f1000 (0x31000)
0x1703dac0000: 0x1703dac0138 - 0x1703db00000 (0x40000)
Change-Id: Iae1a217bbc5c5a88e2cf742db88ead9bb6fc904c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1669744
Commit-Queue: Irina Yatsenko <irinayat@microsoft.com>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Sergiy Belozorov <sergiyb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62316}
2019-06-21 15:22:03 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2019-08-28 22:57:03 +00:00
|
|
|
|
|
Added !mem and !where extensions to windbg.js
The extensions require isolate address to be set but don't rely on calling
any runtime functions, which makes them viable for post-mortem debugging,
if the corresponding memory is included into the dump
!set_iso(isolate_address)
call this function before using !mem or other heap routines
!mem or !mem(\"space1[ space2 ...]\")
prints memory chunks from the 'space' owned by the heap in the
isolate set by !set_iso; valid values for 'space' are:
new, old, map, code, lo [large], nlo [newlarge], ro [readonly]
if no 'space' specified prints memory chunks for all spaces,
e.g. !mem(\"code\"), !mem(\"ro new old\")
!where(address)
prints name of the space and address of the MemoryChunk the
'address' is from, e.g. !where(0x235cb869f9)
Output from !mem would look something like this:
0:000> !mem("old")
Heap at 0x210652b8838
Im address: object area start - end (size)
OldSpace (allocating at: 0x1703dae7a20):
* 0x33d9a8c0000: 0x33d9a8c0138 - 0x33d9a8f1000 (0x31000)
0x1703dac0000: 0x1703dac0138 - 0x1703db00000 (0x40000)
Change-Id: Iae1a217bbc5c5a88e2cf742db88ead9bb6fc904c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1669744
Commit-Queue: Irina Yatsenko <irinayat@microsoft.com>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Sergiy Belozorov <sergiyb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62316}
2019-06-21 15:22:03 +00:00
|
|
|
|
return undefined;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
|
Print memory chunks from spaces in the current Heap
|
|
|
|
|
'isolate_address' should be an int (so in hex must include '0x' prefix).
|
|
|
|
|
'space': space separated string containing "all", "old", "new", "map",
|
|
|
|
|
"code", "ro [readonly]", "lo [large]", "nlo [newlarge]"
|
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
|
function print_memory(space = "all") {
|
|
|
|
|
if (isolate_address == 0) {
|
|
|
|
|
print("Please call !set_iso(isolate_address) first.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let iso = cast(isolate_address, "v8::internal::Isolate");
|
|
|
|
|
let h = iso.heap_;
|
|
|
|
|
print(`Heap at ${h.targetLocation}`);
|
|
|
|
|
|
|
|
|
|
let st = space.toLowerCase().split(" ");
|
|
|
|
|
|
|
|
|
|
print("Im address:\t object area start - end (size)");
|
|
|
|
|
if (st.includes("all") || st.includes("old")) {
|
|
|
|
|
print_memory_chunk_list("OldSpace",
|
|
|
|
|
h.old_space_.memory_chunk_list_.front_,
|
|
|
|
|
h.old_space_.allocation_info_.top_);
|
|
|
|
|
}
|
|
|
|
|
if (st.includes("all") || st.includes("new")) {
|
|
|
|
|
// new space doesn't use the chunk list from its base class but from
|
|
|
|
|
// the to/from semi-spaces it points to
|
|
|
|
|
print_memory_chunk_list("NewSpace_To",
|
|
|
|
|
h.new_space_.to_space_.memory_chunk_list_.front_,
|
|
|
|
|
h.new_space_.allocation_info_.top_,
|
|
|
|
|
h.new_space_.to_space_.age_mark_);
|
|
|
|
|
print_memory_chunk_list("NewSpace_From",
|
|
|
|
|
h.new_space_.from_space_.memory_chunk_list_.front_);
|
|
|
|
|
}
|
|
|
|
|
if (st.includes("all") || st.includes("map")) {
|
|
|
|
|
print_memory_chunk_list("MapSpace",
|
|
|
|
|
h.map_space_.memory_chunk_list_.front_,
|
|
|
|
|
h.map_space_.allocation_info_.top_);
|
|
|
|
|
}
|
|
|
|
|
if (st.includes("all") || st.includes("code")) {
|
|
|
|
|
print_memory_chunk_list("CodeSpace",
|
|
|
|
|
h.code_space_.memory_chunk_list_.front_,
|
|
|
|
|
h.code_space_.allocation_info_.top_);
|
|
|
|
|
}
|
|
|
|
|
if (st.includes("all") || st.includes("large") || st.includes("lo")) {
|
|
|
|
|
print_memory_chunk_list("LargeObjectSpace",
|
|
|
|
|
h.lo_space_.memory_chunk_list_.front_);
|
|
|
|
|
}
|
|
|
|
|
if (st.includes("all") || st.includes("newlarge") || st.includes("nlo")) {
|
|
|
|
|
print_memory_chunk_list("NewLargeObjectSpace",
|
|
|
|
|
h.new_lo_space_.memory_chunk_list_.front_);
|
|
|
|
|
}
|
|
|
|
|
if (st.includes("all") || st.includes("readonly") || st.includes("ro")) {
|
|
|
|
|
print_memory_chunk_list("ReadOnlySpace",
|
|
|
|
|
h.read_only_space_.memory_chunk_list_.front_);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
|
'isolate_address' and 'address' should be ints (so in hex must include '0x'
|
|
|
|
|
prefix).
|
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
|
function print_owning_space(address) {
|
|
|
|
|
if (isolate_address == 0) {
|
|
|
|
|
print("Please call !set_iso(isolate_address) first.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let c = find_chunk(address);
|
|
|
|
|
if (c) {
|
2019-08-28 22:57:03 +00:00
|
|
|
|
print(`${hex(address)} is in ${c.space} (chunk: ${hex(c.address)})`);
|
Added !mem and !where extensions to windbg.js
The extensions require isolate address to be set but don't rely on calling
any runtime functions, which makes them viable for post-mortem debugging,
if the corresponding memory is included into the dump
!set_iso(isolate_address)
call this function before using !mem or other heap routines
!mem or !mem(\"space1[ space2 ...]\")
prints memory chunks from the 'space' owned by the heap in the
isolate set by !set_iso; valid values for 'space' are:
new, old, map, code, lo [large], nlo [newlarge], ro [readonly]
if no 'space' specified prints memory chunks for all spaces,
e.g. !mem(\"code\"), !mem(\"ro new old\")
!where(address)
prints name of the space and address of the MemoryChunk the
'address' is from, e.g. !where(0x235cb869f9)
Output from !mem would look something like this:
0:000> !mem("old")
Heap at 0x210652b8838
Im address: object area start - end (size)
OldSpace (allocating at: 0x1703dae7a20):
* 0x33d9a8c0000: 0x33d9a8c0138 - 0x33d9a8f1000 (0x31000)
0x1703dac0000: 0x1703dac0138 - 0x1703db00000 (0x40000)
Change-Id: Iae1a217bbc5c5a88e2cf742db88ead9bb6fc904c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1669744
Commit-Queue: Irina Yatsenko <irinayat@microsoft.com>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Sergiy Belozorov <sergiyb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62316}
2019-06-21 15:22:03 +00:00
|
|
|
|
}
|
|
|
|
|
else {
|
2019-08-28 22:57:03 +00:00
|
|
|
|
print(`Address ${hex(address)} is not in managed heap`);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
|
function print_handles_data(print_handles = false) {
|
|
|
|
|
if (isolate_address == 0) {
|
|
|
|
|
print("Please call !set_iso(isolate_address) first.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let iso = cast(isolate_address, "v8::internal::Isolate");
|
|
|
|
|
let hsd = iso.handle_scope_data_;
|
|
|
|
|
let hsimpl = iso.handle_scope_implementer_;
|
|
|
|
|
|
|
|
|
|
// depth level
|
|
|
|
|
print(`Nested depth level: ${hsd.level}`);
|
|
|
|
|
|
|
|
|
|
// count of handles
|
|
|
|
|
const ptr_size = pointer_size();
|
|
|
|
|
let blocks = hsimpl.blocks_;
|
|
|
|
|
const block_size = 1022; // v8::internal::KB - 2
|
|
|
|
|
const first_block = blocks.data_.address;
|
|
|
|
|
const last_block = (blocks.size_ == 0)
|
|
|
|
|
? first_block
|
|
|
|
|
: first_block + ptr_size * (blocks.size_ - 1);
|
|
|
|
|
|
|
|
|
|
const count = (blocks.size_ == 0)
|
|
|
|
|
? 0
|
|
|
|
|
: (blocks.size_ - 1) * block_size +
|
|
|
|
|
(hsd.next.address - poi(last_block))/ptr_size;
|
|
|
|
|
print(`Currently tracking ${count} local handles`);
|
|
|
|
|
|
|
|
|
|
// print the handles
|
|
|
|
|
if (print_handles && count > 0) {
|
|
|
|
|
for (let block = first_block; block < last_block;
|
|
|
|
|
block += block_size * ptr_size) {
|
|
|
|
|
print(`Handles in block at ${hex(block)}`);
|
|
|
|
|
for (let i = 0; i < block_size; i++) {
|
|
|
|
|
const location = poi(block + i * ptr_size);
|
|
|
|
|
print(` ${hex(location)}->${hex(poi(location))}`);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let location = poi(last_block);
|
|
|
|
|
print(`Handles in block at ${hex(last_block)}`);
|
|
|
|
|
for (let location = poi(last_block); location < hsd.next.address;
|
|
|
|
|
location += ptr_size) {
|
|
|
|
|
print(` ${hex(location)}->${hex(poi(location))}`);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// where will the next handle allocate at?
|
|
|
|
|
const prefix = "Next handle's location will be";
|
|
|
|
|
if (hsd.next.address < hsd.limit.address) {
|
|
|
|
|
print(`${prefix} at ${hex(hsd.next.address)}`);
|
|
|
|
|
}
|
|
|
|
|
else if (hsimpl.spare_) {
|
|
|
|
|
const location = hsimpl.spare_.address;
|
|
|
|
|
print(`${prefix} from the spare block at ${hex(location)}`);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
print(`${prefix} from a new block to be allocated`);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function pad_right(addr) {
|
|
|
|
|
let addr_hex = hex(addr);
|
|
|
|
|
return `${addr_hex}${" ".repeat(pointer_size() * 2 + 2 - addr_hex.length)}`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO irinayat: would be nice to identify handles and smi as well
|
|
|
|
|
function dp(addr, count = 10) {
|
|
|
|
|
if (isolate_address == 0) {
|
|
|
|
|
print(`To see where objects are located, run !set_iso.`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!Number.isSafeInteger(int(addr))) {
|
|
|
|
|
print(`${hex(addr)} doesn't look like a valid address`);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const ptr_size = pointer_size();
|
|
|
|
|
let aligned_addr = addr - (addr % ptr_size);
|
|
|
|
|
let val = poi(aligned_addr);
|
|
|
|
|
let iter = 0;
|
|
|
|
|
while (val && iter < count) {
|
|
|
|
|
const augm_map = is_map(val) ? "map" : "";
|
|
|
|
|
const augm_obj = is_likely_object(val) && !is_map(val) ? "obj" : "";
|
|
|
|
|
const augm_other = !is_map(val) && !is_likely_object(val) ? "val" : "";
|
|
|
|
|
let c = find_chunk(val);
|
|
|
|
|
const augm_space = c ? ` in ${c.space}` : "";
|
|
|
|
|
const augm = `${augm_map}${augm_obj}${augm_other}${augm_space}`;
|
|
|
|
|
|
|
|
|
|
print(`${pad_right(aligned_addr)} ${pad_right(val)} ${augm}`);
|
|
|
|
|
|
|
|
|
|
aligned_addr += ptr_size;
|
|
|
|
|
val = poi(aligned_addr);
|
|
|
|
|
iter++;
|
Added !mem and !where extensions to windbg.js
The extensions require isolate address to be set but don't rely on calling
any runtime functions, which makes them viable for post-mortem debugging,
if the corresponding memory is included into the dump
!set_iso(isolate_address)
call this function before using !mem or other heap routines
!mem or !mem(\"space1[ space2 ...]\")
prints memory chunks from the 'space' owned by the heap in the
isolate set by !set_iso; valid values for 'space' are:
new, old, map, code, lo [large], nlo [newlarge], ro [readonly]
if no 'space' specified prints memory chunks for all spaces,
e.g. !mem(\"code\"), !mem(\"ro new old\")
!where(address)
prints name of the space and address of the MemoryChunk the
'address' is from, e.g. !where(0x235cb869f9)
Output from !mem would look something like this:
0:000> !mem("old")
Heap at 0x210652b8838
Im address: object area start - end (size)
OldSpace (allocating at: 0x1703dae7a20):
* 0x33d9a8c0000: 0x33d9a8c0138 - 0x33d9a8f1000 (0x31000)
0x1703dac0000: 0x1703dac0138 - 0x1703db00000 (0x40000)
Change-Id: Iae1a217bbc5c5a88e2cf742db88ead9bb6fc904c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1669744
Commit-Queue: Irina Yatsenko <irinayat@microsoft.com>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Sergiy Belozorov <sergiyb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62316}
2019-06-21 15:22:03 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-11 21:00:20 +00:00
|
|
|
|
/*=============================================================================
|
|
|
|
|
Initialize short aliased names for the most common commands
|
|
|
|
|
=============================================================================*/
|
|
|
|
|
function initializeScript() {
|
|
|
|
|
return [
|
|
|
|
|
new host.functionAlias(help, "help"),
|
|
|
|
|
new host.functionAlias(print_object_from_handle, "jlh"),
|
|
|
|
|
new host.functionAlias(print_object, "job"),
|
|
|
|
|
new host.functionAlias(print_objects_array, "jobs"),
|
|
|
|
|
new host.functionAlias(print_js_stack, "jst"),
|
|
|
|
|
|
Added !mem and !where extensions to windbg.js
The extensions require isolate address to be set but don't rely on calling
any runtime functions, which makes them viable for post-mortem debugging,
if the corresponding memory is included into the dump
!set_iso(isolate_address)
call this function before using !mem or other heap routines
!mem or !mem(\"space1[ space2 ...]\")
prints memory chunks from the 'space' owned by the heap in the
isolate set by !set_iso; valid values for 'space' are:
new, old, map, code, lo [large], nlo [newlarge], ro [readonly]
if no 'space' specified prints memory chunks for all spaces,
e.g. !mem(\"code\"), !mem(\"ro new old\")
!where(address)
prints name of the space and address of the MemoryChunk the
'address' is from, e.g. !where(0x235cb869f9)
Output from !mem would look something like this:
0:000> !mem("old")
Heap at 0x210652b8838
Im address: object area start - end (size)
OldSpace (allocating at: 0x1703dae7a20):
* 0x33d9a8c0000: 0x33d9a8c0138 - 0x33d9a8f1000 (0x31000)
0x1703dac0000: 0x1703dac0138 - 0x1703db00000 (0x40000)
Change-Id: Iae1a217bbc5c5a88e2cf742db88ead9bb6fc904c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1669744
Commit-Queue: Irina Yatsenko <irinayat@microsoft.com>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Sergiy Belozorov <sergiyb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62316}
2019-06-21 15:22:03 +00:00
|
|
|
|
new host.functionAlias(set_isolate_address, "set_iso"),
|
2019-08-28 22:57:03 +00:00
|
|
|
|
new host.functionAlias(module_name, "set_module"),
|
Added !mem and !where extensions to windbg.js
The extensions require isolate address to be set but don't rely on calling
any runtime functions, which makes them viable for post-mortem debugging,
if the corresponding memory is included into the dump
!set_iso(isolate_address)
call this function before using !mem or other heap routines
!mem or !mem(\"space1[ space2 ...]\")
prints memory chunks from the 'space' owned by the heap in the
isolate set by !set_iso; valid values for 'space' are:
new, old, map, code, lo [large], nlo [newlarge], ro [readonly]
if no 'space' specified prints memory chunks for all spaces,
e.g. !mem(\"code\"), !mem(\"ro new old\")
!where(address)
prints name of the space and address of the MemoryChunk the
'address' is from, e.g. !where(0x235cb869f9)
Output from !mem would look something like this:
0:000> !mem("old")
Heap at 0x210652b8838
Im address: object area start - end (size)
OldSpace (allocating at: 0x1703dae7a20):
* 0x33d9a8c0000: 0x33d9a8c0138 - 0x33d9a8f1000 (0x31000)
0x1703dac0000: 0x1703dac0138 - 0x1703db00000 (0x40000)
Change-Id: Iae1a217bbc5c5a88e2cf742db88ead9bb6fc904c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1669744
Commit-Queue: Irina Yatsenko <irinayat@microsoft.com>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Sergiy Belozorov <sergiyb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62316}
2019-06-21 15:22:03 +00:00
|
|
|
|
new host.functionAlias(print_memory, "mem"),
|
|
|
|
|
new host.functionAlias(print_owning_space, "where"),
|
2019-08-28 22:57:03 +00:00
|
|
|
|
new host.functionAlias(print_handles_data, "handles"),
|
|
|
|
|
|
|
|
|
|
new host.functionAlias(print_object_prev, "jo_prev"),
|
|
|
|
|
new host.functionAlias(print_object_next, "jo_next"),
|
|
|
|
|
new host.functionAlias(print_objects_in_range, "jo_in_range"),
|
|
|
|
|
new host.functionAlias(print_objects_tree, "jot"),
|
|
|
|
|
|
|
|
|
|
new host.functionAlias(dp, "dp"),
|
Added !mem and !where extensions to windbg.js
The extensions require isolate address to be set but don't rely on calling
any runtime functions, which makes them viable for post-mortem debugging,
if the corresponding memory is included into the dump
!set_iso(isolate_address)
call this function before using !mem or other heap routines
!mem or !mem(\"space1[ space2 ...]\")
prints memory chunks from the 'space' owned by the heap in the
isolate set by !set_iso; valid values for 'space' are:
new, old, map, code, lo [large], nlo [newlarge], ro [readonly]
if no 'space' specified prints memory chunks for all spaces,
e.g. !mem(\"code\"), !mem(\"ro new old\")
!where(address)
prints name of the space and address of the MemoryChunk the
'address' is from, e.g. !where(0x235cb869f9)
Output from !mem would look something like this:
0:000> !mem("old")
Heap at 0x210652b8838
Im address: object area start - end (size)
OldSpace (allocating at: 0x1703dae7a20):
* 0x33d9a8c0000: 0x33d9a8c0138 - 0x33d9a8f1000 (0x31000)
0x1703dac0000: 0x1703dac0138 - 0x1703db00000 (0x40000)
Change-Id: Iae1a217bbc5c5a88e2cf742db88ead9bb6fc904c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1669744
Commit-Queue: Irina Yatsenko <irinayat@microsoft.com>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Sergiy Belozorov <sergiyb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62316}
2019-06-21 15:22:03 +00:00
|
|
|
|
|
2019-03-11 21:00:20 +00:00
|
|
|
|
new host.functionAlias(set_user_js_bp, "jsbp"),
|
|
|
|
|
]
|
|
|
|
|
}
|