bool BinaryReaderObjdumpBase::OnError(const Error&) { // Tell the BinaryReader that this error is "handled" for all passes other // than the prepass. When the error is handled the default message will be // suppressed. return options_->mode != ObjdumpMode::Prepass;
}
Result BinaryReaderObjdumpBase::BeginModule(uint32_t version) { switch (options_->mode) { case ObjdumpMode::Headers:
printf("\n");
printf("Sections:\n\n"); break; case ObjdumpMode::Details:
printf("\n");
printf("Section Details:\n\n"); break; case ObjdumpMode::Disassemble:
printf("\n");
printf("Code Disassembly:\n\n"); break; case ObjdumpMode::Prepass: {
std::string_view basename = GetBasename(options_->filename); if (basename == "-") {
basename = "<stdin>";
}
printf("%s:\tfile format wasm %#x\n", std::string(basename).c_str(),
version); break;
} case ObjdumpMode::RawData: break;
}
Result OnFuncType(Index index,
Index param_count,
Type* param_types,
Index result_count,
Type* result_types) override {
objdump_state_->function_param_counts[index] = param_count; return Result::Ok;
}
Result OnNameEntry(NameSectionSubsection type,
Index index,
std::string_view name) override { switch (type) { // TODO(sbc): remove OnFunctionName in favor of just using // OnNameEntry so that this works /* caseNameSectionSubsection::Function: SetFunctionName(index,name); break;
*/ case NameSectionSubsection::Type:
SetTypeName(index, name); break; case NameSectionSubsection::Global:
SetGlobalName(index, name); break; case NameSectionSubsection::Table:
SetTableName(index, name); break; case NameSectionSubsection::DataSegment:
SetSegmentName(index, name); break; case NameSectionSubsection::Tag:
SetTagName(index, name); break; default: break;
} return Result::Ok;
}
Result OnLocalName(Index function_index,
Index local_index,
std::string_view local_name) override {
SetLocalName(function_index, local_index, local_name); return Result::Ok;
}
Result OnSymbolCount(Index count) override {
objdump_state_->symtab.resize(count); return Result::Ok;
}
class BinaryReaderObjdumpDisassemble : public BinaryReaderObjdumpBase { public: using BinaryReaderObjdumpBase::BinaryReaderObjdumpBase;
std::string BlockSigToString(Type type) const;
Result OnFunction(Index index, Index sig_index) override;
Result BeginFunctionBody(Index index, Offset size) override;
Result EndFunctionBody(Index index) override;
Result OnLocalDeclCount(Index count) override;
Result OnLocalDecl(Index decl_index, Index count, Type type) override;
Result OnOpcode(Opcode Opcode) override;
Result OnOpcodeBare() override;
Result OnOpcodeIndex(Index value) override;
Result OnOpcodeIndexIndex(Index value, Index value2) override;
Result OnOpcodeUint32(uint32_t value) override;
Result OnOpcodeUint32Uint32(uint32_t value, uint32_t value2) override;
Result OnCallIndirectExpr(uint32_t sig_indix, uint32_t table_index) override;
Result OnOpcodeUint32Uint32Uint32(uint32_t value,
uint32_t value2,
uint32_t value3) override;
Result OnOpcodeUint32Uint32Uint32Uint32(uint32_t value,
uint32_t value2,
uint32_t value3,
uint32_t value4) override;
Result OnOpcodeUint64(uint64_t value) override;
Result OnOpcodeF32(uint32_t value) override;
Result OnOpcodeF64(uint64_t value) override;
Result OnOpcodeV128(v128 value) override;
Result OnOpcodeBlockSig(Type sig_type) override;
Result OnOpcodeType(Type type) override;
Result OnBrTableExpr(Index num_targets,
Index* target_depths,
Index default_target_depth) override;
Result OnDelegateExpr(Index) override;
Result OnEndExpr() override;
private: void LogOpcode(constchar* fmt, ...);
Offset current_opcode_offset = 0;
Offset last_opcode_end = 0; int indent_level = 0;
Index next_reloc = 0;
Index current_function_index = 0;
Index local_index_ = 0; bool in_function_body = false; bool skip_next_opcode_ = false;
};
Result BinaryReaderObjdumpDisassemble::OnOpcode(Opcode opcode) {
BinaryReaderObjdumpBase::OnOpcode(opcode); if (!in_function_body) { return Result::Ok;
} if (options_->debug) { constchar* opcode_name = opcode.GetName();
err_stream_->Writef("on_opcode: %#" PRIzx ": %s\n", state->offset,
opcode_name);
}
if (last_opcode_end) { // Takes care of cases where opcode's bytes was a non-canonical leb128 // encoding. In this case, opcode.GetLength() under-reports the length, // since it canonicalizes the opcode. if (state->offset < last_opcode_end + opcode.GetLength()) {
Opcode missing_opcode = Opcode::FromCode(data_[last_opcode_end]); constchar* opcode_name = missing_opcode.GetName();
fprintf(stderr, "error: %#" PRIzx " missing opcode callback at %#" PRIzx " (%#02x=%s)\n",
state->offset, last_opcode_end + 1, data_[last_opcode_end],
opcode_name); return Result::Error;
}
}
void BinaryReaderObjdumpDisassemble::LogOpcode(constchar* fmt, ...) { // BinaryReaderObjdumpDisassemble is only used to disassembly function bodies // so this should never be called for instructions outside of function bodies // (i.e. init expresions).
assert(in_function_body); if (skip_next_opcode_) {
skip_next_opcode_ = false; return;
} const Offset immediate_len = state->offset - current_opcode_offset; const Offset opcode_size = current_opcode.GetLength(); const Offset total_size = opcode_size + immediate_len; // current_opcode_offset has already read past this opcode; rewind it by the // size of this opcode, which may be more than one byte.
Offset offset = current_opcode_offset - opcode_size; const Offset offset_end = offset + total_size;
bool first_line = true; while (offset < offset_end) { // Print bytes, but only display a maximum of IMMEDIATE_OCTET_COUNT on each // line.
printf(" %06" PRIzx ":", GetPrintOffset(offset));
size_t i; for (i = 0; offset < offset_end && i < IMMEDIATE_OCTET_COUNT;
++i, ++offset) {
printf(" %02x", data_[offset]);
} // Fill the rest of the remaining space with spaces. for (; i < IMMEDIATE_OCTET_COUNT; ++i) {
printf(" ");
}
printf(" | ");
if (first_line) {
first_line = false;
// Print disassembly. int indent_level = this->indent_level; switch (current_opcode) { case Opcode::Else: case Opcode::Catch: case Opcode::CatchAll:
indent_level--; break; default: break;
} for (int j = 0; j < indent_level; j++) {
printf(" ");
}
Result BinaryReaderObjdumpDisassemble::OnOpcodeUint64(uint64_t value) { if (!in_function_body) { return Result::Ok;
}
LogOpcode("%" PRIu64, value); return Result::Ok;
}
Result BinaryReaderObjdumpDisassemble::OnOpcodeF32(uint32_t value) { if (!in_function_body) { return Result::Ok;
} char buffer[WABT_MAX_FLOAT_HEX];
WriteFloatHex(buffer, sizeof(buffer), value);
LogOpcode(buffer); return Result::Ok;
}
Result BinaryReaderObjdumpDisassemble::OnOpcodeF64(uint64_t value) { if (!in_function_body) { return Result::Ok;
} char buffer[WABT_MAX_DOUBLE_HEX];
WriteDoubleHex(buffer, sizeof(buffer), value);
LogOpcode(buffer); return Result::Ok;
}
Result BinaryReaderObjdumpDisassemble::OnOpcodeV128(v128 value) { if (!in_function_body) { return Result::Ok;
} // v128 is always dumped as i32x4:
LogOpcode("0x%08x 0x%08x 0x%08x 0x%08x", value.u32(0), value.u32(1),
value.u32(2), value.u32(3)); return Result::Ok;
}
Result BinaryReaderObjdumpDisassemble::OnOpcodeType(Type type) { if (!in_function_body) { return Result::Ok;
} if (current_opcode == Opcode::SelectT) {
LogOpcode(type.GetName().c_str());
} else {
LogOpcode(type.GetRefKindName());
} return Result::Ok;
}
Result BinaryReaderObjdumpDisassemble::OnBrTableExpr(
Index num_targets,
Index* target_depths,
Index default_target_depth) { if (!in_function_body) { return Result::Ok;
}
std::string buffer = std::string(); for (Index i = 0; i < num_targets; i++) {
buffer.append(std::to_string(target_depths[i])).append(" ");
}
buffer.append(std::to_string(default_target_depth));
Result BinaryReaderObjdumpDisassemble::OnDelegateExpr(Index depth) { if (!in_function_body) { return Result::Ok;
} // Because `delegate` ends the block we need to dedent here, and // we don't need to dedent it in LogOpcode. if (indent_level > 0) {
indent_level--;
} return Result::Ok;
}
Result BinaryReaderObjdumpDisassemble::OnEndExpr() { if (!in_function_body) { return Result::Ok;
} if (indent_level > 0) {
indent_level--;
}
LogOpcode(0, nullptr); return Result::Ok;
}
Result BinaryReaderObjdumpDisassemble::OnFunction(Index index,
Index sig_index) {
objdump_state_->function_types[index] = sig_index; return Result::Ok;
}
Result BinaryReaderObjdumpDisassemble::BeginFunctionBody(Index index,
Offset size) {
printf("%06" PRIzx " func[%" PRIindex "]", GetPrintOffset(state->offset),
index); auto name = GetFunctionName(index); if (!name.empty()) {
printf(" <" PRIstringview ">", WABT_PRINTF_STRING_VIEW_ARG(name));
}
printf(":\n");
Result BinaryReaderObjdumpDisassemble::OnOpcodeBlockSig(Type sig_type) { if (!in_function_body) { return Result::Ok;
} if (sig_type != Type::Void) {
LogOpcode("%s", BlockSigToString(sig_type).c_str());
} else {
LogOpcode(nullptr);
}
indent_level++; return Result::Ok;
}
enumclass InitExprType {
Invalid,
I32,
F32,
I64,
F64,
V128,
Global,
FuncRef, // TODO: There isn't a nullref anymore, this just represents ref.null of some // type T.
NullRef,
};
struct InitInst {
Opcode opcode; union {
Index index;
uint32_t i32;
uint32_t f32;
uint64_t i64;
uint64_t f64;
v128 v128_v;
Type type;
} imm;
};
class BinaryReaderObjdump : public BinaryReaderObjdumpBase { public:
BinaryReaderObjdump(const uint8_t* data,
size_t size,
ObjdumpOptions* options,
ObjdumpState* state);
Result EndModule() override;
Result BeginSection(Index section_index,
BinarySection section_type,
Offset size) override;
Result BeginCustomSection(Index section_index,
Offset size,
std::string_view section_name) override;
Result OnTypeCount(Index count) override;
Result OnFuncType(Index index,
Index param_count,
Type* param_types,
Index result_count,
Type* result_types) override;
Result OnStructType(Index index, Index field_count, TypeMut* fields) override;
Result OnArrayType(Index index, TypeMut field) override;
Result OnImportCount(Index count) override;
Result OnImportFunc(Index import_index,
std::string_view module_name,
std::string_view field_name,
Index func_index,
Index sig_index) override;
Result OnImportTable(Index import_index,
std::string_view module_name,
std::string_view field_name,
Index table_index,
Type elem_type, const Limits* elem_limits) override;
Result OnImportMemory(Index import_index,
std::string_view module_name,
std::string_view field_name,
Index memory_index, const Limits* page_limits,
uint32_t page_size) override;
Result OnImportGlobal(Index import_index,
std::string_view module_name,
std::string_view field_name,
Index global_index,
Type type, bool mutable_) override;
Result OnImportTag(Index import_index,
std::string_view module_name,
std::string_view field_name,
Index tag_index,
Index sig_index) override;
Result OnFunctionCount(Index count) override;
Result OnFunction(Index index, Index sig_index) override;
Result OnTableCount(Index count) override;
Result OnTable(Index index,
Type elem_type, const Limits* elem_limits) override;
Result OnMemoryCount(Index count) override;
Result OnMemory(Index index, const Limits* limits,
uint32_t page_size) override;
Result OnGlobalCount(Index count) override;
Result BeginGlobal(Index index, Type type, bool mutable_) override;
Result OnExportCount(Index count) override;
Result OnExport(Index index,
ExternalKind kind,
Index item_index,
std::string_view name) override;
Result OnStartFunction(Index func_index) override;
Result OnDataCount(Index count) override;
Result OnFunctionBodyCount(Index count) override;
Result BeginFunctionBody(Index index, Offset size) override;
Result OnElemSegmentCount(Index count) override;
Result BeginElemSegment(Index index,
Index table_index,
uint8_t flags) override;
Result OnElemSegmentElemType(Index index, Type elem_type) override;
Result OnElemSegmentElemExprCount(Index index, Index count) override;
Result EndGlobalInitExpr(Index index) override { return EndInitExpr(); }
Result BeginElemExpr(Index elem_index, Index expr_index) override {
reading_elem_expr_ = true;
elem_index_ = expr_index;
BeginInitExpr(); return Result::Ok;
}
Result EndElemExpr(Index elem_index, Index expr_index) override {
assert(expr_index == elem_index_); return EndInitExpr();
}
Result OnDataSegmentCount(Index count) override;
Result BeginDataSegment(Index index,
Index memory_index,
uint8_t flags) override;
Result OnDataSegmentData(Index index, constvoid* data,
Address size) override;
Result OnModuleName(std::string_view name) override;
Result OnFunctionName(Index function_index,
std::string_view function_name) override;
Result OnLocalName(Index function_index,
Index local_index,
std::string_view local_name) override;
Result OnNameEntry(NameSectionSubsection type,
Index index,
std::string_view name) override;
Result OnDylinkInfo(uint32_t mem_size,
uint32_t mem_align_log2,
uint32_t table_size,
uint32_t table_align_log2) override;
Result OnDylinkNeededCount(Index count) override;
Result OnDylinkNeeded(std::string_view so_name) override;
Result OnDylinkImportCount(Index count) override;
Result OnDylinkExportCount(Index count) override;
Result OnDylinkImport(std::string_view module,
std::string_view name,
uint32_t flags) override;
Result OnDylinkExport(std::string_view name, uint32_t flags) override;
Result OnRelocCount(Index count, Index section_index) override;
Result OnReloc(RelocType type,
Offset offset,
Index index,
uint32_t addend) override;
Result OnFeature(uint8_t prefix, std::string_view name) override;
Result OnSymbolCount(Index count) override;
Result OnDataSymbol(Index index,
uint32_t flags,
std::string_view name,
Index segment,
uint32_t offset,
uint32_t size) override;
Result OnFunctionSymbol(Index index,
uint32_t flags,
std::string_view name,
Index func_index) override;
Result OnGlobalSymbol(Index index,
uint32_t flags,
std::string_view name,
Index global_index) override;
Result OnSectionSymbol(Index index,
uint32_t flags,
Index section_index) override;
Result OnTagSymbol(Index index,
uint32_t flags,
std::string_view name,
Index tag_index) override;
Result OnTableSymbol(Index index,
uint32_t flags,
std::string_view name,
Index table_index) override;
Result OnSegmentInfoCount(Index count) override;
Result OnSegmentInfo(Index index,
std::string_view name,
Address alignment_log2,
uint32_t flags) override;
Result OnInitFunctionCount(Index count) override;
Result OnInitFunction(uint32_t priority, Index symbol_index) override;
Result OnComdatCount(Index count) override;
Result OnComdatBegin(std::string_view name,
uint32_t flags,
Index count) override;
Result OnComdatEntry(ComdatType kind, Index index) override;
Result OnTagCount(Index count) override;
Result OnTagType(Index index, Index sig_index) override;
Result OnOpcode(Opcode Opcode) override;
Result OnI32ConstExpr(uint32_t value) override;
Result OnI64ConstExpr(uint64_t value) override;
Result OnF32ConstExpr(uint32_t value) override;
Result OnF64ConstExpr(uint64_t value) override;
Result OnRefFuncExpr(Index func_index) override;
Result OnRefNullExpr(Type type) override;
Result OnGlobalGetExpr(Index global_index) override;
Result OnCodeMetadataCount(Index function_index, Index count) override;
Result OnCodeMetadata(Offset code_offset, constvoid* data,
Address size) override;
private:
Result EndInitExpr(); bool ShouldPrintDetails(); void PrintDetails(constchar* fmt, ...);
Result PrintSymbolFlags(uint32_t flags);
Result PrintSegmentFlags(uint32_t flags); void PrintInitExpr(const InitExpr& expr, bool as_unsigned = false, bool with_prefix = true);
Result OnCount(Index count);
// |section_name| and |match_name| are identical for known sections. For // custom sections, |section_name| is "Custom", but |match_name| is the name // of the custom section. constchar* section_name = wabt::GetSectionName(section_code);
std::string match_name(GetSectionName(section_index));
if (expr.insts.empty()) {
PrintDetails("<EMPTY>\n"); return;
}
// We have two different way to print init expressions. One for // extended expressions involving more than one instruction, and // a short form for the more traditional single instruction form. if (expr.insts.size() > 1) {
PrintDetails("("); bool first = true; for (auto& inst : expr.insts) { if (!first) {
PrintDetails(", ");
}
first = false;
PrintDetails("%s", inst.opcode.GetName()); switch (inst.opcode) { case Opcode::I32Const:
PrintDetails(" %d", inst.imm.i32); break; case Opcode::I64Const:
PrintDetails(" %" PRId64, inst.imm.i64); break; case Opcode::F32Const: { char buffer[WABT_MAX_FLOAT_HEX];
WriteFloatHex(buffer, sizeof(buffer), inst.imm.f32);
PrintDetails(" %s\n", buffer); break;
} case Opcode::F64Const: { char buffer[WABT_MAX_DOUBLE_HEX];
WriteDoubleHex(buffer, sizeof(buffer), inst.imm.f64);
PrintDetails(" %s\n", buffer); break;
} case Opcode::GlobalGet: {
PrintDetails(" %" PRIindex, inst.imm.index);
std::string_view name = GetGlobalName(inst.imm.index); if (!name.empty()) {
PrintDetails(" <" PRIstringview ">",
WABT_PRINTF_STRING_VIEW_ARG(name));
} break;
} default: break;
}
}
PrintDetails(")\n"); return;
}
switch (expr.type) { case InitExprType::I32: if (as_unsigned) {
PrintDetails("i32=%u\n", expr.insts[0].imm.i32);
} else {
PrintDetails("i32=%d\n", expr.insts[0].imm.i32);
} break; case InitExprType::I64: if (as_unsigned) {
PrintDetails("i64=%" PRIu64 "\n", expr.insts[0].imm.i64);
} else {
PrintDetails("i64=%" PRId64 "\n", expr.insts[0].imm.i64);
} break; case InitExprType::F64: { char buffer[WABT_MAX_DOUBLE_HEX];
WriteDoubleHex(buffer, sizeof(buffer), expr.insts[0].imm.f64);
PrintDetails("f64=%s\n", buffer); break;
} case InitExprType::F32: { char buffer[WABT_MAX_FLOAT_HEX];
WriteFloatHex(buffer, sizeof(buffer), expr.insts[0].imm.f32);
PrintDetails("f32=%s\n", buffer); break;
} case InitExprType::V128: {
PrintDetails( "v128=0x%08x 0x%08x 0x%08x 0x%08x \n",
expr.insts[0].imm.v128_v.u32(0), expr.insts[0].imm.v128_v.u32(1),
expr.insts[0].imm.v128_v.u32(2), expr.insts[0].imm.v128_v.u32(3)); break;
} case InitExprType::Global: {
PrintDetails("global=%" PRIindex, expr.insts[0].imm.index);
std::string_view name = GetGlobalName(expr.insts[0].imm.index); if (!name.empty()) {
PrintDetails(" <" PRIstringview ">", WABT_PRINTF_STRING_VIEW_ARG(name));
}
PrintDetails("\n"); break;
} case InitExprType::FuncRef: {
PrintDetails("ref.func:%" PRIindex, expr.insts[0].imm.index);
std::string_view name = GetFunctionName(expr.insts[0].imm.index); if (!name.empty()) {
PrintDetails(" <" PRIstringview ">", WABT_PRINTF_STRING_VIEW_ARG(name));
}
PrintDetails("\n"); break;
} case InitExprType::NullRef:
PrintDetails("ref.null %s\n", expr.insts[0].imm.type.GetName().c_str()); break; case InitExprType::Invalid:
PrintDetails("<INVALID>\n"); break;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.