121efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch// Copyright 2016 the V8 project authors. All rights reserved. 221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch// Use of this source code is governed by a BSD-style license that can be 321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch// found in the LICENSE file. 421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch 521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch#include "src/wasm/wasm-debug.h" 621efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch 721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch#include "src/assert-scope.h" 821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch#include "src/debug/debug.h" 921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch#include "src/factory.h" 1021efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch#include "src/isolate.h" 1121efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch#include "src/wasm/module-decoder.h" 1221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch#include "src/wasm/wasm-module.h" 1321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch 1421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdochusing namespace v8::internal; 1521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdochusing namespace v8::internal::wasm; 1621efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch 1721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdochnamespace { 1821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch 1921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdochenum { 2021efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch kWasmDebugInfoWasmObj, 2121efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch kWasmDebugInfoWasmBytesHash, 2221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch kWasmDebugInfoFunctionByteOffsets, 2321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch kWasmDebugInfoNumEntries 2421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch}; 2521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch 2621efce637eb329c94f1323b6a2334a1c977e1a9dBen MurdochByteArray *GetOrCreateFunctionOffsetTable(Handle<WasmDebugInfo> debug_info) { 2721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch Object *offset_table = debug_info->get(kWasmDebugInfoFunctionByteOffsets); 2821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch Isolate *isolate = debug_info->GetIsolate(); 2921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch if (!offset_table->IsUndefined(isolate)) return ByteArray::cast(offset_table); 3021efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch 3121efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch FunctionOffsetsResult function_offsets; 3221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch { 3321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch DisallowHeapAllocation no_gc; 3421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch SeqOneByteString *wasm_bytes = 3521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch wasm::GetWasmBytes(debug_info->wasm_object()); 3621efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch const byte *bytes_start = wasm_bytes->GetChars(); 3721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch const byte *bytes_end = bytes_start + wasm_bytes->length(); 3821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch function_offsets = wasm::DecodeWasmFunctionOffsets(bytes_start, bytes_end); 3921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch } 4021efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch DCHECK(function_offsets.ok()); 4121efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch size_t array_size = 2 * kIntSize * function_offsets.val.size(); 4221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch CHECK_LE(array_size, static_cast<size_t>(kMaxInt)); 4321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch ByteArray *arr = 4421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch *isolate->factory()->NewByteArray(static_cast<int>(array_size)); 4521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch int idx = 0; 4621efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch for (std::pair<int, int> p : function_offsets.val) { 4721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch arr->set_int(idx++, p.first); 4821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch arr->set_int(idx++, p.second); 4921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch } 5021efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch DCHECK_EQ(arr->length(), idx * kIntSize); 5121efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch debug_info->set(kWasmDebugInfoFunctionByteOffsets, arr); 5221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch 5321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch return arr; 5421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch} 5521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch 5621efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdochstd::pair<int, int> GetFunctionOffsetAndLength(Handle<WasmDebugInfo> debug_info, 5721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch int func_index) { 5821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch ByteArray *arr = GetOrCreateFunctionOffsetTable(debug_info); 5921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch DCHECK(func_index >= 0 && func_index < arr->length() / kIntSize / 2); 6021efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch 6121efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch int offset = arr->get_int(2 * func_index); 6221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch int length = arr->get_int(2 * func_index + 1); 6321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch // Assert that it's distinguishable from the "illegal function index" return. 6421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch DCHECK(offset > 0 && length > 0); 6521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch return {offset, length}; 6621efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch} 6721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch 6821efce637eb329c94f1323b6a2334a1c977e1a9dBen MurdochVector<const uint8_t> GetFunctionBytes(Handle<WasmDebugInfo> debug_info, 6921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch int func_index) { 7021efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch SeqOneByteString *module_bytes = 7121efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch wasm::GetWasmBytes(debug_info->wasm_object()); 7221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch std::pair<int, int> offset_and_length = 7321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch GetFunctionOffsetAndLength(debug_info, func_index); 7421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch return Vector<const uint8_t>( 7521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch module_bytes->GetChars() + offset_and_length.first, 7621efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch offset_and_length.second); 7721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch} 7821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch 7921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch} // namespace 8021efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch 8121efce637eb329c94f1323b6a2334a1c977e1a9dBen MurdochHandle<WasmDebugInfo> WasmDebugInfo::New(Handle<JSObject> wasm) { 8221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch Isolate *isolate = wasm->GetIsolate(); 8321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch Factory *factory = isolate->factory(); 8421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch Handle<FixedArray> arr = 8521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch factory->NewFixedArray(kWasmDebugInfoNumEntries, TENURED); 8621efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch arr->set(kWasmDebugInfoWasmObj, *wasm); 8721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch int hash = 0; 8821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch Handle<SeqOneByteString> wasm_bytes(GetWasmBytes(*wasm), isolate); 8921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch { 9021efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch DisallowHeapAllocation no_gc; 9121efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch hash = StringHasher::HashSequentialString( 9221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch wasm_bytes->GetChars(), wasm_bytes->length(), kZeroHashSeed); 9321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch } 9421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch Handle<Object> hash_obj = factory->NewNumberFromInt(hash, TENURED); 9521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch arr->set(kWasmDebugInfoWasmBytesHash, *hash_obj); 9621efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch 9721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch return Handle<WasmDebugInfo>::cast(arr); 9821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch} 9921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch 10021efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdochbool WasmDebugInfo::IsDebugInfo(Object *object) { 10121efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch if (!object->IsFixedArray()) return false; 10221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch FixedArray *arr = FixedArray::cast(object); 10321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch Isolate *isolate = arr->GetIsolate(); 10421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch return arr->length() == kWasmDebugInfoNumEntries && 10521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch IsWasmObject(arr->get(kWasmDebugInfoWasmObj)) && 10621efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch arr->get(kWasmDebugInfoWasmBytesHash)->IsNumber() && 10721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch (arr->get(kWasmDebugInfoFunctionByteOffsets)->IsUndefined(isolate) || 10821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch arr->get(kWasmDebugInfoFunctionByteOffsets)->IsByteArray()); 10921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch} 11021efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch 11121efce637eb329c94f1323b6a2334a1c977e1a9dBen MurdochWasmDebugInfo *WasmDebugInfo::cast(Object *object) { 11221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch DCHECK(IsDebugInfo(object)); 11321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch return reinterpret_cast<WasmDebugInfo *>(object); 11421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch} 11521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch 11621efce637eb329c94f1323b6a2334a1c977e1a9dBen MurdochJSObject *WasmDebugInfo::wasm_object() { 11721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch return JSObject::cast(get(kWasmDebugInfoWasmObj)); 11821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch} 11921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch 12021efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdochbool WasmDebugInfo::SetBreakPoint(int byte_offset) { 12121efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch // TODO(clemensh): Implement this. 12221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch return false; 12321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch} 12421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch 12521efce637eb329c94f1323b6a2334a1c977e1a9dBen MurdochHandle<String> WasmDebugInfo::DisassembleFunction( 12621efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch Handle<WasmDebugInfo> debug_info, int func_index) { 12721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch std::ostringstream disassembly_os; 12821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch 12921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch { 13021efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch Vector<const uint8_t> bytes_vec = GetFunctionBytes(debug_info, func_index); 13121efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch DisallowHeapAllocation no_gc; 13221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch 13321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch base::AccountingAllocator allocator; 13421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch bool ok = PrintAst( 13521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch &allocator, FunctionBodyForTesting(bytes_vec.start(), bytes_vec.end()), 13621efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch disassembly_os, nullptr); 13721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch DCHECK(ok); 13821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch USE(ok); 13921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch } 14021efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch 14121efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch // Unfortunately, we have to copy the string here. 14221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch std::string code_str = disassembly_os.str(); 14321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch CHECK_LE(code_str.length(), static_cast<size_t>(kMaxInt)); 14421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch Factory *factory = debug_info->GetIsolate()->factory(); 14521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch Vector<const char> code_vec(code_str.data(), 14621efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch static_cast<int>(code_str.length())); 14721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch return factory->NewStringFromAscii(code_vec).ToHandleChecked(); 14821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch} 14921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch 15021efce637eb329c94f1323b6a2334a1c977e1a9dBen MurdochHandle<FixedArray> WasmDebugInfo::GetFunctionOffsetTable( 15121efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch Handle<WasmDebugInfo> debug_info, int func_index) { 15221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch class NullBuf : public std::streambuf {}; 15321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch NullBuf null_buf; 15421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch std::ostream null_stream(&null_buf); 15521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch 15621efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch std::vector<std::tuple<uint32_t, int, int>> offset_table_vec; 15721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch 15821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch { 15921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch Vector<const uint8_t> bytes_vec = GetFunctionBytes(debug_info, func_index); 16021efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch DisallowHeapAllocation no_gc; 16121efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch 16221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch v8::base::AccountingAllocator allocator; 16321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch bool ok = PrintAst( 16421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch &allocator, FunctionBodyForTesting(bytes_vec.start(), bytes_vec.end()), 16521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch null_stream, &offset_table_vec); 16621efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch DCHECK(ok); 16721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch USE(ok); 16821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch } 16921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch 17021efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch size_t arr_size = 3 * offset_table_vec.size(); 17121efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch CHECK_LE(arr_size, static_cast<size_t>(kMaxInt)); 17221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch Factory *factory = debug_info->GetIsolate()->factory(); 17321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch Handle<FixedArray> offset_table = 17421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch factory->NewFixedArray(static_cast<int>(arr_size), TENURED); 17521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch 17621efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch int idx = 0; 17721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch for (std::tuple<uint32_t, int, int> elem : offset_table_vec) { 17821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch offset_table->set(idx++, Smi::FromInt(std::get<0>(elem))); 17921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch offset_table->set(idx++, Smi::FromInt(std::get<1>(elem))); 18021efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch offset_table->set(idx++, Smi::FromInt(std::get<2>(elem))); 18121efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch } 18221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch DCHECK_EQ(idx, offset_table->length()); 18321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch 18421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch return offset_table; 18521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch} 186