[tools] Support pointer compression in windbg.js
Change-Id: I63cf6cd9b22ea02846ec40eba214acb21304d418 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1832637 Commit-Queue: Irina Yatsenko <irinayat@microsoft.com> Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Cr-Commit-Position: refs/heads/master@{#64091}
This commit is contained in:
parent
13202d2933
commit
1fb432c457
204
tools/windbg.js
204
tools/windbg.js
@ -20,9 +20,6 @@ function help() {
|
||||
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)");
|
||||
print(" prints 'count' objects from a continuous range of Object");
|
||||
print(" pointers, e.g. !jobs(0x5f7270, 42)");
|
||||
print(" !jst() or !jst");
|
||||
print(" prints javascript stack (output goes into the console)");
|
||||
print(" !jsbp() or !jsbp");
|
||||
@ -119,14 +116,6 @@ 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) {
|
||||
for (let k of Reflect.ownKeys(s)) {
|
||||
// Attempting to print either of:
|
||||
@ -210,6 +199,26 @@ function get_register(name) {
|
||||
.Registers.User[name];
|
||||
}
|
||||
|
||||
// JS doesn't do bitwise operations on large integers, so let's do it ourselves
|
||||
// using hex string representation.
|
||||
function bitwise_and(l, r) {
|
||||
l = hex(l);
|
||||
let l_length = l.length;
|
||||
r = hex(r);
|
||||
let r_length = r.length;
|
||||
let res = "";
|
||||
let length = Math.min(l_length, r_length) - 2; // to account for "0x"
|
||||
for (let i = 1; i <= length; i++) {
|
||||
res = (parseInt(l[l_length - i], 16) & parseInt(r[r_length - i], 16))
|
||||
.toString(16) + res;
|
||||
}
|
||||
return parseInt(res, 16);
|
||||
}
|
||||
|
||||
|
||||
/*=============================================================================
|
||||
Script setup
|
||||
=============================================================================*/
|
||||
// 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
|
||||
// other embedder, run !set_module and provide the module name to use.
|
||||
@ -261,6 +270,25 @@ function module_name(use_this_module) {
|
||||
return module_name_cache;
|
||||
};
|
||||
|
||||
let using_ptr_compr = false;
|
||||
let isolate_address = 0;
|
||||
function set_isolate_address(addr, ptr_compr) {
|
||||
isolate_address = addr;
|
||||
|
||||
if (typeof ptr_compr === 'undefined') {
|
||||
ptr_compr = (bitwise_and(isolate_address, 0xffffffff) == 0);
|
||||
}
|
||||
using_ptr_compr = ptr_compr;
|
||||
|
||||
if (using_ptr_compr) {
|
||||
print("The target is using pointer compression.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*=============================================================================
|
||||
Wrappers around V8's printing functions and other utils for live-debugging
|
||||
=============================================================================*/
|
||||
function make_call(fn) {
|
||||
if (!supports_call_command()) {
|
||||
print("ERROR: This command is supported in live sessions only!");
|
||||
@ -276,16 +304,8 @@ function make_call(fn) {
|
||||
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})`);
|
||||
let output = make_call(`_v8_internal_Print_Object(${decomp(address)})`);
|
||||
|
||||
// skip the first few lines with meta info of .call command
|
||||
let skip_line = true;
|
||||
@ -300,43 +320,13 @@ function print_object(address) {
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
'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);
|
||||
let pobj = poi(location.address); // handles use uncompressed pointers
|
||||
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) {
|
||||
const ptr_size = pointer_size();
|
||||
let ctl = host.namespace.Debugger.Utility.Control;
|
||||
let addr_int = start_address;
|
||||
for (let i = 0; i < count; i++) {
|
||||
const addr_hex = hex(addr_int);
|
||||
|
||||
// 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);
|
||||
|
||||
addr_int += ptr_size;
|
||||
}
|
||||
}
|
||||
|
||||
function print_js_stack() {
|
||||
make_call("_v8_internal_Print_StackTrace()");
|
||||
}
|
||||
@ -350,21 +340,47 @@ function set_user_js_bp() {
|
||||
/*=============================================================================
|
||||
Managed heap related functions (live and post-mortem debugging)
|
||||
=============================================================================*/
|
||||
let isolate_address = 0;
|
||||
function set_isolate_address(addr) {
|
||||
isolate_address = addr;
|
||||
/*-----------------------------------------------------------------------------
|
||||
Pointer compression
|
||||
-----------------------------------------------------------------------------*/
|
||||
function tagged_size() {
|
||||
return using_ptr_compr ? 4 : pointer_size();
|
||||
}
|
||||
|
||||
function get_compressed_ptr_base() {
|
||||
if (!using_ptr_compr) return 0;
|
||||
|
||||
return isolate_address;
|
||||
}
|
||||
|
||||
function decomp(value) {
|
||||
if (value > 0xffffffff) return value;
|
||||
return get_compressed_ptr_base() + value;
|
||||
}
|
||||
|
||||
// Adjust for possible pointer compression ('address' is assumed to be on the
|
||||
// managed heap).
|
||||
function poim(address) {
|
||||
try {
|
||||
// readMemoryValues throws if cannot read from 'address'.
|
||||
return host.memory.readMemoryValues(decomp(address), 1, tagged_size())[0];
|
||||
}
|
||||
catch (e){}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
Exploring objects
|
||||
-----------------------------------------------------------------------------*/
|
||||
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));
|
||||
const map_addr = int(poim(address - 1));
|
||||
if (!Number.isSafeInteger(map_addr)) return false;
|
||||
|
||||
const map_map_addr = int(poi(map_addr - 1));
|
||||
const map_map_addr = int(poim(map_addr - 1));
|
||||
if (!Number.isSafeInteger(map_map_addr)) return false;
|
||||
|
||||
return (map_addr === map_map_addr);
|
||||
@ -375,12 +391,12 @@ function is_likely_object(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));
|
||||
return is_map(poim(address - 1));
|
||||
}
|
||||
|
||||
function find_object_near(aligned_addr, max_distance, step_op) {
|
||||
if (!step_op) {
|
||||
const step = pointer_size();
|
||||
const step = tagged_size();
|
||||
const prev =
|
||||
find_object_near(aligned_addr, max_distance, x => x - step);
|
||||
const next =
|
||||
@ -391,14 +407,14 @@ function find_object_near(aligned_addr, max_distance, step_op) {
|
||||
return (addr - prev <= next - addr) ? prev : next;
|
||||
}
|
||||
|
||||
let maybe_map_addr = poi(aligned_addr);
|
||||
let maybe_map_addr = poim(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);
|
||||
maybe_map_addr = poim(aligned_addr);
|
||||
iters++;
|
||||
}
|
||||
}
|
||||
@ -406,7 +422,7 @@ function find_object_near(aligned_addr, max_distance, step_op) {
|
||||
function find_object_prev(addr, max_distance) {
|
||||
if (!Number.isSafeInteger(int(addr))) return;
|
||||
|
||||
const ptr_size = pointer_size();
|
||||
const ptr_size = tagged_size();
|
||||
const aligned_addr = addr - (addr % ptr_size);
|
||||
return find_object_near(aligned_addr, max_distance, x => x - ptr_size);
|
||||
}
|
||||
@ -414,7 +430,7 @@ function find_object_prev(addr, max_distance) {
|
||||
function find_object_next(addr, max_distance) {
|
||||
if (!Number.isSafeInteger(int(addr))) return;
|
||||
|
||||
const ptr_size = pointer_size();
|
||||
const ptr_size = tagged_size();
|
||||
const aligned_addr = addr - (addr % ptr_size) + ptr_size;
|
||||
return find_object_near(aligned_addr, max_distance, x => x + ptr_size);
|
||||
}
|
||||
@ -427,7 +443,7 @@ function print_object_prev(addr, max_slots = 100) {
|
||||
}
|
||||
else {
|
||||
print(
|
||||
`found object: ${hex(obj_addr + 1)} : ${hex(poi(obj_addr))}`);
|
||||
`found object: ${hex(obj_addr + 1)} : ${hex(poim(obj_addr))}`);
|
||||
}
|
||||
}
|
||||
|
||||
@ -439,7 +455,7 @@ function print_object_next(addr, max_slots = 100) {
|
||||
}
|
||||
else {
|
||||
print(
|
||||
`found object: ${hex(obj_addr + 1)} : ${hex(poi(obj_addr))}`);
|
||||
`found object: ${hex(obj_addr + 1)} : ${hex(poim(obj_addr))}`);
|
||||
}
|
||||
}
|
||||
|
||||
@ -449,8 +465,9 @@ function print_objects_in_range(start, end){
|
||||
if (!Number.isSafeInteger(int(start)) || !Number.isSafeInteger(int(end))) {
|
||||
return;
|
||||
}
|
||||
const ptr_size = tagged_size();
|
||||
if (start < ptr_size || end <= start) return;
|
||||
|
||||
const ptr_size = pointer_size();
|
||||
let iters = (end - start) / ptr_size;
|
||||
let cur = start;
|
||||
print(`===============================================`);
|
||||
@ -461,7 +478,7 @@ function print_objects_in_range(start, end){
|
||||
let obj = find_object_next(cur, iters);
|
||||
if (obj) {
|
||||
count++;
|
||||
print(`${hex(obj + 1)} : ${hex(poi(obj))}`);
|
||||
print(`${hex(obj + 1)} : ${hex(poim(obj))}`);
|
||||
iters = (end - cur) / ptr_size;
|
||||
}
|
||||
cur = obj + ptr_size;
|
||||
@ -481,10 +498,10 @@ function print_objects_tree(root, depth_limit) {
|
||||
let path = [];
|
||||
|
||||
function impl(obj, depth, depth_limit) {
|
||||
const ptr_size = pointer_size();
|
||||
const ptr_size = tagged_size();
|
||||
// print the current object and its map pointer
|
||||
const this_obj =
|
||||
`${" ".repeat(2 * depth)}${hex(obj)} : ${hex(poi(obj - 1))}`;
|
||||
`${" ".repeat(2 * depth)}${hex(obj)} : ${hex(poim(obj - 1))}`;
|
||||
const cutoff = depth_limit && depth == depth_limit - 1;
|
||||
print(`${this_obj}${cutoff ? " (...)" : ""}`);
|
||||
if (cutoff) return;
|
||||
@ -499,7 +516,7 @@ function print_objects_tree(root, depth_limit) {
|
||||
let seen = new Set(path);
|
||||
while (!is_likely_object(cur + 1) && iter < 100) {
|
||||
iter++;
|
||||
let field = poi(cur);
|
||||
let field = poim(cur);
|
||||
if (is_likely_object(field)) {
|
||||
if (seen.has(field)) {
|
||||
print(
|
||||
@ -518,7 +535,7 @@ function print_objects_tree(root, depth_limit) {
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
Memory in each Space is organized into a linked list of memory chunks
|
||||
Memory spaces
|
||||
-----------------------------------------------------------------------------*/
|
||||
const NEVER_EVACUATE = 1 << 7; // see src\heap\spaces.h
|
||||
|
||||
@ -591,12 +608,6 @@ function find_chunk(address) {
|
||||
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.");
|
||||
@ -649,16 +660,13 @@ function print_memory(space = "all") {
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
'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;
|
||||
}
|
||||
|
||||
address = decomp(address);
|
||||
let c = find_chunk(address);
|
||||
if (c) {
|
||||
print(`${hex(address)} is in ${c.space} (chunk: ${hex(c.address)})`);
|
||||
@ -669,7 +677,7 @@ function print_owning_space(address) {
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
|
||||
Handles
|
||||
-----------------------------------------------------------------------------*/
|
||||
function print_handles_data(print_handles = false) {
|
||||
if (isolate_address == 0) {
|
||||
@ -732,6 +740,9 @@ function print_handles_data(print_handles = false) {
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
dp
|
||||
-----------------------------------------------------------------------------*/
|
||||
function pad_right(addr) {
|
||||
let addr_hex = hex(addr);
|
||||
return `${addr_hex}${" ".repeat(pointer_size() * 2 + 2 - addr_hex.length)}`;
|
||||
@ -748,26 +759,35 @@ function dp(addr, count = 10) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ptr_size = pointer_size();
|
||||
const ptr_size = tagged_size();
|
||||
let aligned_addr = addr - (addr % ptr_size);
|
||||
let val = poi(aligned_addr);
|
||||
let val = poim(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 map = is_map(val);
|
||||
const obj = is_likely_object(val) && !map;
|
||||
|
||||
const augm_map = map ? "map" : "";
|
||||
const augm_obj = obj ? "obj" : "";
|
||||
const augm_other = !map && !obj ? "val" : "";
|
||||
|
||||
let c = find_chunk(decomp(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}`);
|
||||
const full_ptr = using_ptr_compr ?
|
||||
pad_right((map || obj) ? decomp(val) : val) : "";
|
||||
print(`${pad_right(aligned_addr)} ${pad_right(val)} ${full_ptr} ${augm}`);
|
||||
|
||||
aligned_addr += ptr_size;
|
||||
val = poi(aligned_addr);
|
||||
val = poim(aligned_addr);
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
Remembered Sets
|
||||
-----------------------------------------------------------------------------*/
|
||||
// set ids: 0 = OLD_TO_NEW, 1 = 0 = OLD_TO_OLD
|
||||
function print_remembered_set(chunk_addr, set_id = 0) {
|
||||
if (!chunk_addr) {
|
||||
@ -809,6 +829,7 @@ function print_remembered_set(chunk_addr, set_id = 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ptr_size = tagged_size();
|
||||
let count = 0;
|
||||
for (let s = 0; s < sets_count; s++){
|
||||
const buckets_count = rs[s].buckets_.Count();
|
||||
@ -826,9 +847,9 @@ function print_remembered_set(chunk_addr, set_id = 0) {
|
||||
for (let bit = 0; bit < 32; bit++){
|
||||
if (cell & mask) {
|
||||
count++;
|
||||
const slot_offset = (b * 32 * 32 + c * 32 + bit) * 8;
|
||||
const slot_offset = (b * 32 * 32 + c * 32 + bit) * ptr_size;
|
||||
const slot = rs[s].page_start_ + slot_offset;
|
||||
print(` ${hex(slot)} -> ${hex(poi(slot))}`);
|
||||
print(` ${hex(slot)} -> ${hex(poim(slot))}`);
|
||||
}
|
||||
mask = mask << 1;
|
||||
}
|
||||
@ -849,7 +870,6 @@ function initializeScript() {
|
||||
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"),
|
||||
|
||||
new host.functionAlias(set_isolate_address, "set_iso"),
|
||||
|
Loading…
Reference in New Issue
Block a user