Commit 1fb432c4 authored by Irina Yatsenko's avatar Irina Yatsenko Committed by Commit Bot

[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: 's avatarUlan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#64091}
parent 13202d29
...@@ -20,9 +20,6 @@ function help() { ...@@ -20,9 +20,6 @@ function help() {
print(" e.g. !jlh(\"key\") or !jlh(\"this->receiver_\")"); print(" e.g. !jlh(\"key\") or !jlh(\"this->receiver_\")");
print(" !job(address_or_taggedint)"); print(" !job(address_or_taggedint)");
print(" prints object at the address, e.g. !job(0x235cb869f9)"); 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(" !jst() or !jst");
print(" prints javascript stack (output goes into the console)"); print(" prints javascript stack (output goes into the console)");
print(" !jsbp() or !jsbp"); print(" !jsbp() or !jsbp");
...@@ -119,14 +116,6 @@ function print(s) { ...@@ -119,14 +116,6 @@ function print(s) {
host.diagnostics.debugLog(s + "\n"); 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) { function inspect(s) {
for (let k of Reflect.ownKeys(s)) { for (let k of Reflect.ownKeys(s)) {
// Attempting to print either of: // Attempting to print either of:
...@@ -210,6 +199,26 @@ function get_register(name) { ...@@ -210,6 +199,26 @@ function get_register(name) {
.Registers.User[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 // 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 // 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. // other embedder, run !set_module and provide the module name to use.
...@@ -261,6 +270,25 @@ function module_name(use_this_module) { ...@@ -261,6 +270,25 @@ function module_name(use_this_module) {
return module_name_cache; 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) { function make_call(fn) {
if (!supports_call_command()) { if (!supports_call_command()) {
print("ERROR: This command is supported in live sessions only!"); print("ERROR: This command is supported in live sessions only!");
...@@ -276,16 +304,8 @@ function make_call(fn) { ...@@ -276,16 +304,8 @@ function make_call(fn) {
return output; 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) { 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 // skip the first few lines with meta info of .call command
let skip_line = true; let skip_line = true;
...@@ -300,43 +320,13 @@ function print_object(address) { ...@@ -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) { function print_object_from_handle(handle_to_object) {
let handle = host.evaluateExpression(handle_to_object); let handle = host.evaluateExpression(handle_to_object);
let location = handle.location_; let location = handle.location_;
let pobj = poi(location.address); let pobj = poi(location.address); // handles use uncompressed pointers
print_object(pobj); 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() { function print_js_stack() {
make_call("_v8_internal_Print_StackTrace()"); make_call("_v8_internal_Print_StackTrace()");
} }
...@@ -350,21 +340,47 @@ function set_user_js_bp() { ...@@ -350,21 +340,47 @@ function set_user_js_bp() {
/*============================================================================= /*=============================================================================
Managed heap related functions (live and post-mortem debugging) Managed heap related functions (live and post-mortem debugging)
=============================================================================*/ =============================================================================*/
let isolate_address = 0; /*-----------------------------------------------------------------------------
function set_isolate_address(addr) { Pointer compression
isolate_address = addr; -----------------------------------------------------------------------------*/
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) { function is_map(addr) {
let address = int(addr); let address = int(addr);
if (!Number.isSafeInteger(address) || address % 2 == 0) return false; if (!Number.isSafeInteger(address) || address % 2 == 0) return false;
// the first field in all objects, including maps, is a map pointer, but for // 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. // 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; 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; if (!Number.isSafeInteger(map_map_addr)) return false;
return (map_addr === map_map_addr); return (map_addr === map_map_addr);
...@@ -375,12 +391,12 @@ function is_likely_object(addr) { ...@@ -375,12 +391,12 @@ function is_likely_object(addr) {
if (!Number.isSafeInteger(address) || address % 2 == 0) return false; if (!Number.isSafeInteger(address) || address % 2 == 0) return false;
// the first field in all objects must be a map pointer // 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) { function find_object_near(aligned_addr, max_distance, step_op) {
if (!step_op) { if (!step_op) {
const step = pointer_size(); const step = tagged_size();
const prev = const prev =
find_object_near(aligned_addr, max_distance, x => x - step); find_object_near(aligned_addr, max_distance, x => x - step);
const next = const next =
...@@ -391,14 +407,14 @@ function find_object_near(aligned_addr, max_distance, step_op) { ...@@ -391,14 +407,14 @@ function find_object_near(aligned_addr, max_distance, step_op) {
return (addr - prev <= next - addr) ? prev : next; return (addr - prev <= next - addr) ? prev : next;
} }
let maybe_map_addr = poi(aligned_addr); let maybe_map_addr = poim(aligned_addr);
let iters = 0; let iters = 0;
while (maybe_map_addr && iters < max_distance) { while (maybe_map_addr && iters < max_distance) {
if (is_map(maybe_map_addr)) { if (is_map(maybe_map_addr)) {
return aligned_addr; return aligned_addr;
} }
aligned_addr = step_op(aligned_addr); aligned_addr = step_op(aligned_addr);
maybe_map_addr = poi(aligned_addr); maybe_map_addr = poim(aligned_addr);
iters++; iters++;
} }
} }
...@@ -406,7 +422,7 @@ function find_object_near(aligned_addr, max_distance, step_op) { ...@@ -406,7 +422,7 @@ function find_object_near(aligned_addr, max_distance, step_op) {
function find_object_prev(addr, max_distance) { function find_object_prev(addr, max_distance) {
if (!Number.isSafeInteger(int(addr))) return; if (!Number.isSafeInteger(int(addr))) return;
const ptr_size = pointer_size(); const ptr_size = tagged_size();
const aligned_addr = addr - (addr % ptr_size); const aligned_addr = addr - (addr % ptr_size);
return find_object_near(aligned_addr, max_distance, x => x - 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) { ...@@ -414,7 +430,7 @@ function find_object_prev(addr, max_distance) {
function find_object_next(addr, max_distance) { function find_object_next(addr, max_distance) {
if (!Number.isSafeInteger(int(addr))) return; 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; const aligned_addr = addr - (addr % ptr_size) + ptr_size;
return find_object_near(aligned_addr, max_distance, x => x + 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) { ...@@ -427,7 +443,7 @@ function print_object_prev(addr, max_slots = 100) {
} }
else { else {
print( 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) { ...@@ -439,7 +455,7 @@ function print_object_next(addr, max_slots = 100) {
} }
else { else {
print( 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){ ...@@ -449,8 +465,9 @@ function print_objects_in_range(start, end){
if (!Number.isSafeInteger(int(start)) || !Number.isSafeInteger(int(end))) { if (!Number.isSafeInteger(int(start)) || !Number.isSafeInteger(int(end))) {
return; 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 iters = (end - start) / ptr_size;
let cur = start; let cur = start;
print(`===============================================`); print(`===============================================`);
...@@ -461,7 +478,7 @@ function print_objects_in_range(start, end){ ...@@ -461,7 +478,7 @@ function print_objects_in_range(start, end){
let obj = find_object_next(cur, iters); let obj = find_object_next(cur, iters);
if (obj) { if (obj) {
count++; count++;
print(`${hex(obj + 1)} : ${hex(poi(obj))}`); print(`${hex(obj + 1)} : ${hex(poim(obj))}`);
iters = (end - cur) / ptr_size; iters = (end - cur) / ptr_size;
} }
cur = obj + ptr_size; cur = obj + ptr_size;
...@@ -481,10 +498,10 @@ function print_objects_tree(root, depth_limit) { ...@@ -481,10 +498,10 @@ function print_objects_tree(root, depth_limit) {
let path = []; let path = [];
function impl(obj, depth, depth_limit) { function impl(obj, depth, depth_limit) {
const ptr_size = pointer_size(); const ptr_size = tagged_size();
// print the current object and its map pointer // print the current object and its map pointer
const this_obj = 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; const cutoff = depth_limit && depth == depth_limit - 1;
print(`${this_obj}${cutoff ? " (...)" : ""}`); print(`${this_obj}${cutoff ? " (...)" : ""}`);
if (cutoff) return; if (cutoff) return;
...@@ -499,7 +516,7 @@ function print_objects_tree(root, depth_limit) { ...@@ -499,7 +516,7 @@ function print_objects_tree(root, depth_limit) {
let seen = new Set(path); let seen = new Set(path);
while (!is_likely_object(cur + 1) && iter < 100) { while (!is_likely_object(cur + 1) && iter < 100) {
iter++; iter++;
let field = poi(cur); let field = poim(cur);
if (is_likely_object(field)) { if (is_likely_object(field)) {
if (seen.has(field)) { if (seen.has(field)) {
print( print(
...@@ -518,7 +535,7 @@ function print_objects_tree(root, depth_limit) { ...@@ -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 const NEVER_EVACUATE = 1 << 7; // see src\heap\spaces.h
...@@ -591,12 +608,6 @@ function find_chunk(address) { ...@@ -591,12 +608,6 @@ function find_chunk(address) {
return undefined; 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") { function print_memory(space = "all") {
if (isolate_address == 0) { if (isolate_address == 0) {
print("Please call !set_iso(isolate_address) first."); print("Please call !set_iso(isolate_address) first.");
...@@ -649,16 +660,13 @@ function print_memory(space = "all") { ...@@ -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) { function print_owning_space(address) {
if (isolate_address == 0) { if (isolate_address == 0) {
print("Please call !set_iso(isolate_address) first."); print("Please call !set_iso(isolate_address) first.");
return; return;
} }
address = decomp(address);
let c = find_chunk(address); let c = find_chunk(address);
if (c) { if (c) {
print(`${hex(address)} is in ${c.space} (chunk: ${hex(c.address)})`); print(`${hex(address)} is in ${c.space} (chunk: ${hex(c.address)})`);
...@@ -669,7 +677,7 @@ function print_owning_space(address) { ...@@ -669,7 +677,7 @@ function print_owning_space(address) {
} }
/*----------------------------------------------------------------------------- /*-----------------------------------------------------------------------------
Handles
-----------------------------------------------------------------------------*/ -----------------------------------------------------------------------------*/
function print_handles_data(print_handles = false) { function print_handles_data(print_handles = false) {
if (isolate_address == 0) { if (isolate_address == 0) {
...@@ -732,6 +740,9 @@ function print_handles_data(print_handles = false) { ...@@ -732,6 +740,9 @@ function print_handles_data(print_handles = false) {
} }
} }
/*-----------------------------------------------------------------------------
dp
-----------------------------------------------------------------------------*/
function pad_right(addr) { function pad_right(addr) {
let addr_hex = hex(addr); let addr_hex = hex(addr);
return `${addr_hex}${" ".repeat(pointer_size() * 2 + 2 - addr_hex.length)}`; return `${addr_hex}${" ".repeat(pointer_size() * 2 + 2 - addr_hex.length)}`;
...@@ -748,26 +759,35 @@ function dp(addr, count = 10) { ...@@ -748,26 +759,35 @@ function dp(addr, count = 10) {
return; return;
} }
const ptr_size = pointer_size(); const ptr_size = tagged_size();
let aligned_addr = addr - (addr % ptr_size); let aligned_addr = addr - (addr % ptr_size);
let val = poi(aligned_addr); let val = poim(aligned_addr);
let iter = 0; let iter = 0;
while (val && iter < count) { while (val && iter < count) {
const augm_map = is_map(val) ? "map" : ""; const map = is_map(val);
const augm_obj = is_likely_object(val) && !is_map(val) ? "obj" : ""; const obj = is_likely_object(val) && !map;
const augm_other = !is_map(val) && !is_likely_object(val) ? "val" : "";
let c = find_chunk(val); 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_space = c ? ` in ${c.space}` : "";
const augm = `${augm_map}${augm_obj}${augm_other}${augm_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; aligned_addr += ptr_size;
val = poi(aligned_addr); val = poim(aligned_addr);
iter++; iter++;
} }
} }
/*-----------------------------------------------------------------------------
Remembered Sets
-----------------------------------------------------------------------------*/
// set ids: 0 = OLD_TO_NEW, 1 = 0 = OLD_TO_OLD // set ids: 0 = OLD_TO_NEW, 1 = 0 = OLD_TO_OLD
function print_remembered_set(chunk_addr, set_id = 0) { function print_remembered_set(chunk_addr, set_id = 0) {
if (!chunk_addr) { if (!chunk_addr) {
...@@ -809,6 +829,7 @@ function print_remembered_set(chunk_addr, set_id = 0) { ...@@ -809,6 +829,7 @@ function print_remembered_set(chunk_addr, set_id = 0) {
return; return;
} }
const ptr_size = tagged_size();
let count = 0; let count = 0;
for (let s = 0; s < sets_count; s++){ for (let s = 0; s < sets_count; s++){
const buckets_count = rs[s].buckets_.Count(); const buckets_count = rs[s].buckets_.Count();
...@@ -826,9 +847,9 @@ function print_remembered_set(chunk_addr, set_id = 0) { ...@@ -826,9 +847,9 @@ function print_remembered_set(chunk_addr, set_id = 0) {
for (let bit = 0; bit < 32; bit++){ for (let bit = 0; bit < 32; bit++){
if (cell & mask) { if (cell & mask) {
count++; 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; const slot = rs[s].page_start_ + slot_offset;
print(` ${hex(slot)} -> ${hex(poi(slot))}`); print(` ${hex(slot)} -> ${hex(poim(slot))}`);
} }
mask = mask << 1; mask = mask << 1;
} }
...@@ -849,7 +870,6 @@ function initializeScript() { ...@@ -849,7 +870,6 @@ function initializeScript() {
new host.functionAlias(help, "help"), new host.functionAlias(help, "help"),
new host.functionAlias(print_object_from_handle, "jlh"), new host.functionAlias(print_object_from_handle, "jlh"),
new host.functionAlias(print_object, "job"), new host.functionAlias(print_object, "job"),
new host.functionAlias(print_objects_array, "jobs"),
new host.functionAlias(print_js_stack, "jst"), new host.functionAlias(print_js_stack, "jst"),
new host.functionAlias(set_isolate_address, "set_iso"), new host.functionAlias(set_isolate_address, "set_iso"),
......
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