26 std::vector<int>* function_body_offsets) {
30 {}, function_body_offsets);
32 out.ToDisassemblyCollector(collector);
37 std::vector<int>* function_body_offsets) {
45 out <<
"Decoding error: " << error.
message() <<
" at offset "
47 out.ToDisassemblyCollector(collector);
54 std::move(offsets), function_body_offsets);
56 out.ToDisassemblyCollector(collector);
65 collector->
AddLine(l.data, l.len - 1, l.bytecode_offset);
72 std::ostream& os, std::vector<uint32_t>* offsets) {
76 Zone zone(&allocator,
"Wasm disassembler");
77 bool shared =
module->type(func.sig_index).is_shared;
84 const bool print_offsets =
false;
85 sb.
WriteTo(os, print_offsets, offsets);
96 std::vector<uint32_t>* collect_offsets =
nullptr;
104 uint32_t function_body_offset, std::ostream& os,
105 std::vector<uint32_t>* offsets) {
124 case kExprS128LoadMem:
125 case kExprS128StoreMem:
127 case kExprS128Load8x8S:
128 case kExprS128Load8x8U:
129 case kExprS128Load16x4S:
130 case kExprS128Load16x4U:
131 case kExprS128Load32x2S:
132 case kExprS128Load32x2U:
133 case kExprS128Load64Splat:
134 case kExprS128Load64Zero:
135 case kExprS128Load64Lane:
136 case kExprS128Store64Lane:
138 case kExprS128Load32Splat:
139 case kExprS128Load32Zero:
140 case kExprS128Load32Lane:
141 case kExprS128Store32Lane:
143 case kExprS128Load16Splat:
144 case kExprS128Load16Lane:
145 case kExprS128Store16Lane:
147 case kExprS128Load8Splat:
148 case kExprS128Load8Lane:
149 case kExprS128Store8Lane:
152#define CASE(Opcode, ...) \
153 case kExpr##Opcode: \
154 return GetLoadType(kExpr##Opcode).size_log_2();
157#define CASE(Opcode, ...) \
158 case kExpr##Opcode: \
159 return GetStoreType(kExpr##Opcode).size_log_2();
163#define CASE(Opcode, Type) \
164 case kExpr##Opcode: \
165 return ElementSizeLog2Of(MachineType::Type().representation());
180 for (uint32_t
i = 0;
i <
sig->parameter_count();
i++) {
182 names->PrintLocalName(out, func_index,
i, indices_as_comments);
184 names->PrintValueType(out,
sig->GetParam(
i));
187 }
else if (
sig->parameter_count() > 0) {
189 for (uint32_t
i = 0;
i <
sig->parameter_count();
i++) {
191 names->PrintValueType(out,
sig->GetParam(
i));
195 for (
size_t i = 0;
i <
sig->return_count();
i++) {
197 names->PrintValueType(out,
sig->GetReturn(
i));
203 const uint8_t*
end) {
204 for (
const uint8_t* ptr =
start; ptr <
end; ptr++) {
206 if (b < 32 || b >= 127 || b ==
'"' || b ==
'\\') {
209 out << static_cast<char>(b);
220 uint32_t* first_instruction_offset) {
222 int base_indentation = indentation.
current();
225 out << indentation <<
"(func ";
231 out.set_current_line_bytecode_offset(
pc_offset());
239 out <<
"Failed to decode locals\n";
242 for (uint32_t
i =
static_cast<uint32_t
>(
sig_->parameter_count());
244 out << indentation <<
"(local ";
252 out.set_current_line_bytecode_offset(
pc_offset());
253 if (first_instruction_offset) *first_instruction_offset =
pc_offset();
261 if (opcode == kExprEnd || opcode == kExprElse || opcode == kExprCatch ||
262 opcode == kExprCatchAll || opcode == kExprDelegate) {
263 if (indentation.
current() >= base_indentation) {
268 if (opcode == kExprElse || opcode == kExprCatch ||
269 opcode == kExprCatchAll || opcode == kExprBlock || opcode == kExprIf ||
270 opcode == kExprLoop || opcode == kExprTry || opcode == kExprTryTable) {
271 indentation.increase();
275 if (opcode == kExprEnd) {
276 if (indentation.current() < base_indentation) {
277 out <<
";; Unexpected end byte";
278 }
else if (indentation.current() == base_indentation) {
283 if (
label.start !=
nullptr) {
292 if (opcode == kExprBlock || opcode == kExprIf || opcode == kExprLoop ||
293 opcode == kExprTry || opcode == kExprTryTable) {
310 out <<
"Beyond end of code";
319 if (opcode == kExprEnd &&
pc_ + 1 ==
end_)
break;
336 constexpr size_t kBufferSize =
sizeof(number) * 2 + 2;
343 }
while (number > 0);
346 size_t length =
static_cast<size_t>(
end - ptr);
347 char* output = out.allocate(length);
348 memcpy(output, ptr, length);
354template <
typename Val
idationTag>
363 int depth = imm_depth;
373 if (label_info.
start !=
nullptr) {
390 out_ <<
" (signature: " << sig_index <<
" INVALID)";
395 if (imm.
sig.
all().begin() ==
nullptr) {
411 if (type.has_index())
use_type(type.ref_index());
439 return "catch_all_ref";
546 if (imm.
index == 0)
return;
569 if (imm.
value >= 0) {
570 out_ <<
" " <<
static_cast<uint64_t
>(imm.
value);
572 out_ <<
" -" << ((~static_cast<uint64_t>(imm.
value)) + 1);
579 out_ << (1 / f < 0 ?
" -0.0" :
" 0.0");
580 }
else if (std::isinf(f)) {
581 out_ << (f > 0 ?
" inf" :
" -inf");
582 }
else if (std::isnan(f)) {
584 uint32_t payload = bits & 0x7F'FFFFu;
585 uint32_t signbit = bits >> 31;
586 if (payload == 0x40'0000u) {
587 out_ << (signbit == 1 ?
" -nan" :
" nan");
589 out_ << (signbit == 1 ?
" -nan:" :
" +nan:");
593 std::ostringstream o;
597 o << std::setprecision(std::numeric_limits<float>::max_digits10) << f;
598 out_ <<
" " << o.str();
603 double d = imm.
value;
605 out_ << (1 / d < 0 ?
" -0.0" :
" 0.0");
606 }
else if (std::isinf(d)) {
607 out_ << (d > 0 ?
" inf" :
" -inf");
608 }
else if (std::isnan(d)) {
610 uint64_t payload = bits & 0xF'FFFF'FFFF'FFFFull;
611 uint64_t signbit = bits >> 63;
612 if (payload == 0x8'0000'0000'0000ull) {
613 out_ << (signbit == 1 ?
" -nan" :
" nan");
615 out_ << (signbit == 1 ?
" -nan:" :
" +nan:");
620 std::string_view str =
628 for (
int i = 0;
i < 16;
i++) {
634 for (
int i = 0;
i < 4;
i++) {
636 for (
int j = 3; j >= 0; j--) {
637 uint8_t b = imm.
value[
i * 4 + j];
658 static constexpr uint32_t kMaxCharsPrinted = 40;
664 const uint8_t*
end =
start + kMaxCharsPrinted - 1;
721 Printer imm_printer(out,
this);
744 &unused_detected_features,
this};
745 constexpr bool kNoVerifyFunctions =
false;
755 std::unique_ptr<OffsetsProvider> offsets_provider,
756 std::vector<int>* function_body_offsets)
762 zone_(allocator,
"disassembler zone"),
763 offsets_(offsets_provider.release()),
764 function_body_offsets_(function_body_offsets) {
766 offsets_ = std::make_unique<OffsetsProvider>();
778 out_ << indentation <<
"(type ";
784 if (type.is_final)
out_ <<
"final ";
790 const ArrayType* atype = type.array_type;
792 if (type.is_shared)
out_ <<
" shared";
799 if (type.is_shared)
out_ <<
" shared";
812 if (type.is_shared)
out_ <<
" shared";
813 bool break_lines =
sig->parameter_count() +
sig->return_count() > 2;
814 for (uint32_t
i = 0;
i <
sig->parameter_count();
i++) {
822 for (uint32_t
i = 0;
i <
sig->return_count();
i++) {
830 out_ << (has_super ?
")))" :
"))");
836 size_t num_tags =
module_->tags.size();
837 std::vector<bool> exported_tags(num_tags,
false);
843 out_ << indentation <<
"(module";
852 uint32_t recgroup_index = 0;
854 bool in_explicit_recgroup =
false;
855 for (uint32_t
i = 0;
i <
module_->types.size();
i++) {
860 out_ << indentation <<
"(rec";
864 DCHECK(!in_explicit_recgroup);
865 recgroup =
offsets_->recgroup(recgroup_index++);
868 in_explicit_recgroup =
true;
869 indentation.increase();
879 in_explicit_recgroup =
false;
885 out_ << indentation <<
")";
886 recgroup =
offsets_->recgroup(recgroup_index++);
889 while (recgroup.
valid()) {
894 out_ << indentation <<
"(rec)";
895 recgroup =
offsets_->recgroup(recgroup_index++);
899 for (uint32_t
i = 0;
i <
module_->import_table.size();
i++) {
900 const WasmImport&
import = module_->import_table[i];
903 switch (
import.
kind) {
935 if (
module_->memories[
import.index].exported) {
945 if (exported_tags[
import.index]) {
955 for (uint32_t
i =
module_->num_imported_tables; i < module_->
tables.size();
960 out_ << indentation <<
"(table ";
968 uint32_t num_memories =
static_cast<uint32_t
>(
module_->memories.size());
969 for (uint32_t memory_index = 0; memory_index < num_memories; ++memory_index) {
971 if (memory.imported)
continue;
973 out_ << indentation <<
"(memory ";
981 for (uint32_t
i =
module_->num_imported_tags; i < module_->tags.size();
i++) {
984 out_ << indentation <<
"(tag ";
992 size_t num_strings =
module_->stringref_literals.size();
993 for (uint32_t
i = 0;
i < num_strings;
i++) {
996 out_ << indentation <<
"(string \"";
1004 for (uint32_t
i =
module_->num_imported_globals; i < module_->globals.size();
1009 out_ << indentation <<
"(global ";
1018 if (
module_->start_function_index >= 0) {
1020 out_ << indentation <<
"(start ";
1027 for (uint32_t
i = 0;
i <
module_->elem_segments.size();
i++) {
1030 out_ << indentation <<
"(elem ";
1065 size_t num_defined_functions =
1069 for (uint32_t
i =
module_->num_imported_functions;
1070 i < module_->functions.size();
i++) {
1073 out_ << indentation <<
"(func ";
1083 code.begin(), code.end(), func->
code.
offset(),
1085 uint32_t first_instruction_offset;
1087 &first_instruction_offset);
1093 out_ <<
"<truncated...>";
1099 for (uint32_t
i = 0;
i <
module_->data_segments.size();
i++) {
1102 out_ << indentation <<
"(data";
1107 if (data.shared)
out_ <<
" shared";
1120 out_ <<
"<truncated...>";
1128 out_ << indentation <<
")";
1133 out_ <<
" (import \"";
1144 out_ <<
" (export \"";
1151 if (mutability)
out_ <<
"(mut ";
1153 if (mutability)
out_ <<
")";
1157 if (table.shared)
out_ <<
" shared";
1158 out_ <<
" " << table.initial_size <<
" ";
1159 if (table.has_maximum_size)
out_ << table.maximum_size <<
" ";
1164 out_ <<
" " << memory.initial_pages;
1165 if (memory.has_maximum_pages)
out_ <<
" " << memory.maximum_pages;
1166 if (memory.is_shared)
out_ <<
" shared";
1177 switch (init.
kind()) {
1184 out_ <<
" (ref.null ";
1189 out_ <<
" (ref.func ";
1202 d.DecodeGlobalInitializer(
out_);
1208 for (uint32_t
i = 0;
i <
sig->parameter_count();
i++) {
1222 i::wasm::PrintStringAsJSON(
out_,
start_, ref);
1233 case '\b': out <<
"\\b";
break;
1234 case '\t': out <<
"\\t";
break;
1235 case '\n': out <<
"\\n";
break;
1236 case '\f': out <<
"\\f";
break;
1237 case '\r': out <<
"\\r";
break;
1238 case ' ': out <<
' ';
break;
1239 case '!': out <<
'!';
break;
1240 case '"': out <<
"\\\"";
break;
1246 }
else if (b != 127 && b !=
'\\') {
1247 out << static_cast<char>(b);
1248 }
else if (b ==
'\\') {
1258 uint32_t byte_offset) {
constexpr T * begin() const
constexpr T * end() const
virtual void ReserveLineCount(size_t count)=0
virtual void AddLine(const char *src, size_t length, uint32_t bytecode_offset)=0
auto Returns(ReturnTypes... return_types) const
base::Vector< const T > all() const
ValueType element_type() const
constexpr uint32_t index() const
constexpr Kind kind() const
constexpr int32_t i32_value() const
V8_EXPORT_PRIVATE WireBytesRef wire_bytes_ref() const
constexpr HeapType type() const
base::EmbeddedVector< char, kMaxErrorMsg > buffer
uint8_t read_u8(const uint8_t *pc, Name< ValidationTag > msg="expected 1 byte")
std::pair< uint32_t, uint32_t > read_u32v(const uint8_t *pc, Name< ValidationTag > name="LEB32")
void consume_bytes(uint32_t size, const char *name="skip")
uint32_t pc_offset() const
const uint8_t * end() const
std::pair< WasmOpcode, uint32_t > read_prefixed_opcode(const uint8_t *pc, Name< ValidationTag > name="prefixed opcode")
std::set< uint32_t > used_types_
uint32_t label_occurrence_index_
std::vector< LabelInfo > label_stack_
WasmOpcode current_opcode_
const ModuleWireBytes wire_bytes_
void DecodeAsWat(MultiLineStringBuilder &out, Indentation indentation, FunctionHeader include_header=kPrintHeader, uint32_t *first_instruction_offset=nullptr)
uint32_t PrintImmediatesAndGetLength(StringBuilder &out)
uint32_t label_generation_index_
LabelInfo & label_info(int depth)
MultiLineStringBuilder * out_
void DecodeGlobalInitializer(StringBuilder &out)
void PrintHexNumber(StringBuilder &out, uint64_t number)
static constexpr HeapType Index(ModuleTypeIndex index, bool shared, RefTypeKind kind, Exactness exact=Exactness::kAnySubtype)
constexpr bool is_index() const
constexpr ModuleTypeIndex ref_index() const
Indentation Extra(int extra)
ModuleResult DecodeModule(bool validate_functions)
ConstantExpression consume_element_segment_entry(WasmModule *module, const WasmElemSegment &segment)
void LineBreakOrSpace(bool break_lines, Indentation indentation, uint32_t byte_offset)
void PrintString(WireBytesRef ref)
V8_EXPORT_PRIVATE ModuleDisassembler(MultiLineStringBuilder &out, const WasmModule *module, NamesProvider *names, const ModuleWireBytes wire_bytes, AccountingAllocator *allocator, std::unique_ptr< OffsetsProvider > offsets_provider={}, std::vector< int > *function_body_offsets=nullptr)
const WasmModule * module_
void PrintTable(const WasmTable &table)
void PrintTagSignature(const FunctionSig *sig)
void PrintExportName(ImportExportKindCode kind, uint32_t index)
V8_EXPORT_PRIVATE void PrintTypeDefinition(uint32_t type_index, Indentation indendation, IndexAsComment index_as_comment)
void PrintMemory(const WasmMemory &memory)
const ModuleWireBytes wire_bytes_
void PrintInitExpression(const ConstantExpression &init, ValueType expected_type)
V8_EXPORT_PRIVATE void PrintModule(Indentation indentation, size_t max_mb)
MultiLineStringBuilder & out_
std::vector< int > * function_body_offsets_
V8_EXPORT_PRIVATE ~ModuleDisassembler()
std::unique_ptr< OffsetsProvider > offsets_
void PrintMutableType(bool mutability, ValueType type)
void PrintImportName(const WasmImport &import)
void PrintGlobal(const WasmGlobal &global)
void PrintStringAsJSON(WireBytesRef ref)
void set_current_line_bytecode_offset(uint32_t offset)
size_t ApproximateSizeMB()
void WriteTo(std::ostream &out, bool print_offsets, std::vector< uint32_t > *collect_offsets=nullptr)
uint32_t current_line_bytecode_offset()
std::vector< Line > lines_
void ToDisassemblyCollector(v8::debug::DisassemblyCollector *collector)
void NextLine(uint32_t byte_offset)
void PatchLabel(LabelInfo &label, const char *label_source)
void PrintLabelName(StringBuilder &out, uint32_t function_index, uint32_t label_index, uint32_t fallback_index)
void PrintGlobalName(StringBuilder &out, uint32_t global_index, IndexAsComment index_as_comment=kDontPrintIndex)
void PrintTagName(StringBuilder &out, uint32_t tag_index, IndexAsComment index_as_comment=kDontPrintIndex)
void PrintDataSegmentName(StringBuilder &out, uint32_t data_segment_index, IndexAsComment index_as_comment=kDontPrintIndex)
void PrintLocalName(StringBuilder &out, uint32_t function_index, uint32_t local_index, IndexAsComment index_as_comment=kDontPrintIndex)
void PrintValueType(StringBuilder &out, ValueType type)
void PrintTypeName(StringBuilder &out, uint32_t type_index, IndexAsComment index_as_comment=kDontPrintIndex)
void PrintFunctionName(StringBuilder &out, uint32_t function_index, FunctionNamesBehavior behavior=kWasmInternal, IndexAsComment index_as_comment=kDontPrintIndex)
void PrintHeapType(StringBuilder &out, HeapType type)
void PrintFieldName(StringBuilder &out, uint32_t struct_index, uint32_t field_index, IndexAsComment index_as_comment=kDontPrintIndex)
void PrintMemoryName(StringBuilder &out, uint32_t memory_index, IndexAsComment index_as_comment=kDontPrintIndex)
void PrintElementSegmentName(StringBuilder &out, uint32_t element_segment_index, IndexAsComment index_as_comment=kDontPrintIndex)
void PrintTableName(StringBuilder &out, uint32_t table_index, IndexAsComment index_as_comment=kDontPrintIndex)
std::vector< uint32_t > tag_offsets_
std::vector< RecGroup > recgroups_
V8_EXPORT_PRIVATE void CollectOffsets(const WasmModule *module, base::Vector< const uint8_t > wire_bytes)
std::vector< uint32_t > table_offsets_
uint32_t num_imported_tags_
std::vector< uint32_t > type_offsets_
uint32_t num_imported_tables_
std::vector< uint32_t > global_offsets_
uint32_t num_imported_globals_
std::vector< uint32_t > element_offsets_
std::vector< uint32_t > data_offsets_
std::vector< uint32_t > import_offsets_
const char * start() const
void write(const uint8_t *data, size_t n)
bool mutability(uint32_t index) const
uint32_t field_count() const
ValueType field(uint32_t index) const
static uint32_t OpcodeLength(WasmDecoder *decoder, const uint8_t *pc, ImmediateObservers &... ios)
const WasmModule * module_
uint32_t DecodeLocals(const uint8_t *pc)
ValueType local_type(uint32_t index) const
static constexpr WasmEnabledFeatures All()
const std::string & message() const &
static constexpr const char * OpcodeName(WasmOpcode)
static constexpr bool IsPrefixOpcode(WasmOpcode)
uint32_t end_offset() const
#define ATOMIC_STORE_OP_LIST(V)
ZoneVector< RpoNumber > & result
#define ATOMIC_OP_LIST(type)
const base::Vector< const uint8_t > wire_bytes_
V8_INLINE Dest bit_cast(Source const &source)
constexpr Vector< T > VectorOf(T *start, size_t size)
void DisassembleFunction(const WasmModule *module, int func_index, base::Vector< const uint8_t > wire_bytes, NamesProvider *names, std::ostream &os)
constexpr bool kSkipFunctionTypesInTypeSection
void PrintStringRaw(StringBuilder &out, const uint8_t *start, const uint8_t *end)
static constexpr char kUpperHexChars[]
constexpr IndexAsComment kIndicesAsComments
static constexpr char kHexChars[]
ModuleResult DecodeWasmModuleForDisassembler(base::Vector< const uint8_t > wire_bytes, ITracer *tracer)
void Disassemble(const WasmModule *module, ModuleWireBytes wire_bytes, NamesProvider *names, v8::debug::DisassemblyCollector *collector, std::vector< int > *function_body_offsets)
constexpr IndependentValueType kWasmI32
V8_EXPORT_PRIVATE void PrintSignatureOneLine(StringBuilder &out, const FunctionSig *sig, uint32_t func_index, NamesProvider *names, bool param_names, IndexAsComment indices_as_comments=NamesProvider::kDontPrintIndex)
constexpr ModuleTypeIndex kNoSuperType
std::unique_ptr< OffsetsProvider > AllocateOffsetsProvider()
void DisassembleFunctionImpl(const WasmModule *module, int func_index, base::Vector< const uint8_t > function_body, ModuleWireBytes module_bytes, NamesProvider *names, std::ostream &os, std::vector< uint32_t > *offsets)
constexpr bool kSkipDataSegmentNames
uint32_t GetDefaultAlignment(WasmOpcode opcode)
V8_EXPORT_PRIVATE void PrintStringAsJSON(StringBuilder &out, const uint8_t *start, WireBytesRef ref)
constexpr IndependentValueType kWasmI64
kWasmInternalFunctionIndirectPointerTag kProtectedInstanceDataOffset sig
kMemory0SizeOffset Address kNewAllocationLimitAddressOffset Address kOldAllocationLimitAddressOffset uint8_t kGlobalsStartOffset kJumpTableStartOffset std::atomic< uint32_t > kTieringBudgetArrayOffset kDataSegmentStartsOffset kElementSegmentsOffset kInstanceObjectOffset kMemoryObjectsOffset kTaggedGlobalsBufferOffset tables
V8_EXPORT_PRIVATE FlagValues v8_flags
std::string_view DoubleToStringView(double v, base::Vector< char > buffer)
#define DCHECK_GE(v1, v2)
#define DCHECK(condition)
#define DCHECK_EQ(v1, v2)
uint32_t name_section_index
base::Vector< const uint8_t > GetFunctionBytes(const WasmFunction *function) const
uint32_t start_type_index
uint32_t elements_wire_bytes_offset
ConstantExpression offset
ImportExportKindCode kind
ModuleTypeIndex sig_index
std::vector< TypeDefinition > types
std::vector< WasmElemSegment > elem_segments
std::vector< WasmImport > import_table
std::vector< WasmFunction > functions
uint32_t num_imported_functions
std::vector< WasmTag > tags
std::vector< WasmGlobal > globals
std::vector< WasmDataSegment > data_segments
std::vector< WasmTable > tables
#define V8_UNLIKELY(condition)
const wasm::WasmModule * module_
#define FOREACH_LOAD_MEM_OPCODE(V)
#define FOREACH_STORE_MEM_OPCODE(V)