/* * Copyright (c) 2020 Bitdefender * SPDX-License-Identifier: Apache-2.0 */ #include "disasm.hpp" #include #include #include using namespace rapidjson; static void _start_object(Writer &writer) { writer.StartObject(); } static void _start_object(Writer &writer, const char *key) { writer.Key(key); writer.StartObject(); } static void _end_object(Writer &writer) { writer.EndObject(); } static void _start_array(Writer &writer) { writer.StartArray(); } static void _start_array(Writer &writer, const char *key) { writer.Key(key); writer.StartArray(); } static void _end_array(Writer &writer) { writer.EndArray(); } static void _write_uint(Writer &writer, unsigned int value) { writer.Uint(value); } static void _write_uint(Writer &writer, const char *key, unsigned int value) { writer.Key(key); writer.Uint(value); } static void _write_int(Writer &writer, int value) { writer.Int(value); } static void _write_int(Writer &writer, const char *key, int value) { writer.Key(key); writer.Int(value); } static void _write_uint64(Writer &writer, uint64_t value) { writer.Int(value); } static void _write_uint64(Writer &writer, const char *key, uint64_t value) { writer.Key(key); writer.Int(value); } static void _write_int64(Writer &writer, int64_t value) { writer.Int(value); } static void _write_int64(Writer &writer, const char *key, int64_t value) { writer.Key(key); writer.Int(value); } static void _write_string(Writer &writer, const std::string& value) { writer.String(value.c_str()); } static void _write_string(Writer &writer, const char *key, const std::string& value) { writer.Key(key); writer.String(value.c_str()); } static void _write_string(Writer &writer, const char *value) { writer.String(value); } static void _write_string(Writer &writer, const char *key, const char *value) { writer.Key(key); writer.String(value); } static void _write_bool(Writer &writer, bool value) { writer.Bool(value); } static void _write_bool(Writer &writer, const char *key, bool value) { writer.Key(key); writer.Bool(value); } static int _disasm_size_to_int(const uint8_t mode) { switch (mode) { case 0: return 16; case 1: return 32; case 2: return 64; } return mode; } static void _write_rex(Writer &writer, const INSTRUX *instrux) { if (!instrux->HasRex) return; _start_object(writer, "rex"); _write_uint(writer, "value", instrux->Rex.Rex); _write_uint(writer, "b", static_cast(instrux->Rex.b)); _write_uint(writer, "x", static_cast(instrux->Rex.x)); _write_uint(writer, "r", static_cast(instrux->Rex.r)); _write_uint(writer, "w", static_cast(instrux->Rex.w)); _end_object(writer); } static void _write_modrm(Writer &writer, const INSTRUX *instrux) { if (!instrux->HasModRm) return; _start_object(writer, "modrm"); _write_uint(writer, "value", instrux->ModRm.ModRm); _write_uint(writer, "rm", static_cast(instrux->ModRm.rm)); _write_uint(writer, "reg", static_cast(instrux->ModRm.reg)); _write_uint(writer, "mod", static_cast(instrux->ModRm.mod)); _end_object(writer); } static void _write_sib(Writer &writer, const INSTRUX *instrux) { if (!instrux->HasSib) return; _start_object(writer, "sib"); _write_uint(writer, "value", instrux->Sib.Sib); _write_uint(writer, "base", static_cast(instrux->Sib.base)); _write_uint(writer, "index", static_cast(instrux->Sib.index)); _write_uint(writer, "scale", static_cast(instrux->Sib.scale)); _end_object(writer); } static void _write_drex(Writer &writer, const INSTRUX *instrux) { if (!instrux->HasDrex) return; _start_object(writer, "drex"); _write_uint(writer, "value", instrux->Drex.Drex); _write_uint(writer, "b", static_cast(instrux->Drex.b)); _write_uint(writer, "x", static_cast(instrux->Drex.x)); _write_uint(writer, "r", static_cast(instrux->Drex.r)); _write_uint(writer, "oc", static_cast(instrux->Drex.oc0)); _write_uint(writer, "vd", static_cast(instrux->Drex.vd)); _write_uint(writer, "d", static_cast(instrux->Drex.d)); _end_object(writer); } static void _write_vex2(Writer &writer, const INSTRUX *instrux) { if (!instrux->HasVex || ND_VEXM_2B != instrux->VexMode) return; _start_object(writer, "vex2"); _start_array(writer, "value"); _write_uint(writer, instrux->Vex2.Vex[0]); _write_uint(writer, instrux->Vex2.Vex[1]); _end_array(writer); _write_uint(writer, "op", instrux->Vex2.op); _write_uint(writer, "p", static_cast(instrux->Vex2.p)); _write_uint(writer, "l", static_cast(instrux->Vex2.l)); _write_uint(writer, "v", static_cast(instrux->Vex2.v)); _write_uint(writer, "r", static_cast(instrux->Vex2.r)); _end_object(writer); } static void _write_vex3(Writer &writer, const INSTRUX *instrux) { if (!instrux->HasVex || ND_VEXM_3B != instrux->VexMode) return; _start_object(writer, "vex3"); _start_array(writer, "value"); _write_uint(writer, instrux->Vex3.Vex[0]); _write_uint(writer, instrux->Vex3.Vex[1]); _write_uint(writer, instrux->Vex3.Vex[2]); _end_array(writer); _write_uint(writer, "op", instrux->Vex3.op); _write_uint(writer, "m", static_cast(instrux->Vex3.m)); _write_uint(writer, "b", static_cast(instrux->Vex3.b)); _write_uint(writer, "x", static_cast(instrux->Vex3.x)); _write_uint(writer, "r", static_cast(instrux->Vex3.r)); _write_uint(writer, "p", static_cast(instrux->Vex3.p)); _write_uint(writer, "l", static_cast(instrux->Vex3.l)); _write_uint(writer, "v", static_cast(instrux->Vex3.v)); _write_uint(writer, "w", static_cast(instrux->Vex3.w)); _end_object(writer); } static void _write_xop(Writer &writer, const INSTRUX *instrux) { if (!instrux->HasXop) return; _start_object(writer, "xop"); _start_array(writer, "value"); _write_uint(writer, instrux->Xop.Xop[0]); _write_uint(writer, instrux->Xop.Xop[1]); _write_uint(writer, instrux->Xop.Xop[2]); _end_array(writer); _write_uint(writer, "op", instrux->Xop.op); _write_uint(writer, "m", static_cast(instrux->Xop.m)); _write_uint(writer, "b", static_cast(instrux->Xop.b)); _write_uint(writer, "x", static_cast(instrux->Xop.x)); _write_uint(writer, "r", static_cast(instrux->Xop.r)); _write_uint(writer, "p", static_cast(instrux->Xop.p)); _write_uint(writer, "l", static_cast(instrux->Xop.l)); _write_uint(writer, "v", static_cast(instrux->Xop.v)); _write_uint(writer, "w", static_cast(instrux->Xop.w)); _end_object(writer); } static void _write_evex(Writer &writer, const INSTRUX *instrux) { if (!instrux->HasEvex) return; _start_object(writer, "evex"); _start_array(writer, "value"); _write_uint(writer, instrux->Evex.Evex[0]); _write_uint(writer, instrux->Evex.Evex[1]); _write_uint(writer, instrux->Evex.Evex[2]); _write_uint(writer, instrux->Evex.Evex[3]); _end_array(writer); _write_uint(writer, "op", instrux->Evex.op); _write_uint(writer, "m", static_cast(instrux->Evex.m)); _write_uint(writer, "zero", static_cast(instrux->Evex.zero)); _write_uint(writer, "rp", static_cast(instrux->Evex.rp)); _write_uint(writer, "b", static_cast(instrux->Evex.b)); _write_uint(writer, "x", static_cast(instrux->Evex.x)); _write_uint(writer, "r", static_cast(instrux->Evex.r)); _write_uint(writer, "p", static_cast(instrux->Evex.p)); _write_uint(writer, "one", static_cast(instrux->Evex.one)); _write_uint(writer, "v", static_cast(instrux->Evex.v)); _write_uint(writer, "w", static_cast(instrux->Evex.w)); _write_uint(writer, "a", static_cast(instrux->Evex.a)); _write_uint(writer, "vp", static_cast(instrux->Evex.vp)); _write_uint(writer, "bm", static_cast(instrux->Evex.bm)); _write_uint(writer, "l", static_cast(instrux->Evex.l)); _write_uint(writer, "z", static_cast(instrux->Evex.z)); _end_object(writer); } static void _write_exs(Writer &writer, const INSTRUX *instrux) { _start_object(writer, "exs"); _write_uint(writer, "w", static_cast(instrux->Exs.w)); _write_uint(writer, "r", static_cast(instrux->Exs.r)); _write_uint(writer, "x", static_cast(instrux->Exs.x)); _write_uint(writer, "b", static_cast(instrux->Exs.b)); _write_uint(writer, "rp", static_cast(instrux->Exs.rp)); _write_uint(writer, "p", static_cast(instrux->Exs.p)); _write_uint(writer, "m", static_cast(instrux->Exs.m)); _write_uint(writer, "l", static_cast(instrux->Exs.l)); _write_uint(writer, "v", static_cast(instrux->Exs.v)); _write_uint(writer, "vp", static_cast(instrux->Exs.vp)); _write_uint(writer, "bm", static_cast(instrux->Exs.bm)); _write_uint(writer, "e", static_cast(instrux->Exs.e)); _write_uint(writer, "z", static_cast(instrux->Exs.z)); _write_uint(writer, "k", static_cast(instrux->Exs.k)); _write_uint(writer, "s", static_cast(instrux->Exs.s)); _end_object(writer); } static void _write_prefixes(Writer &writer, const INSTRUX *instrux) { _start_array(writer, "prefixes"); if (instrux->HasRex) _write_string(writer, "rex"); if (instrux->HasVex) _write_string(writer, "vex"); if (instrux->HasXop) _write_string(writer, "xop"); if (instrux->HasEvex) _write_string(writer, "evex"); if (instrux->HasMvex) _write_string(writer, "mvex"); if (instrux->HasOpSize) _write_string(writer, "op_size"); if (instrux->HasAddrSize) _write_string(writer, "addr_size"); if (instrux->HasLock) _write_string(writer, "lock"); if (instrux->HasRepnzXacquireBnd) _write_string(writer, "repnz_xacquire_bnd"); if (instrux->HasRepRepzXrelease) _write_string(writer, "rep_repz_xrelease"); if (instrux->HasSeg) _write_string(writer, "seg"); _end_array(writer); } static void _write_chunks(Writer &writer, const INSTRUX *instrux) { _start_array(writer, "chunks"); if (instrux->HasModRm) _write_string(writer, "mod_rm"); if (instrux->HasSib) _write_string(writer, "sib"); if (instrux->HasDrex) _write_string(writer, "drex"); if (instrux->HasDisp) _write_string(writer, "disp"); if (instrux->HasAddr) _write_string(writer, "addr"); if (instrux->HasMoffset) _write_string(writer, "moffset"); if (instrux->HasImm1) _write_string(writer, "imm1"); if (instrux->HasImm2) _write_string(writer, "imm2"); if (instrux->HasImm3) _write_string(writer, "imm3"); if (instrux->HasRelOffs) _write_string(writer, "rel_offs"); if (instrux->HasSseImm) _write_string(writer, "sse_imm"); if (instrux->HasCompDisp) _write_string(writer, "comp_disp"); if (instrux->HasBroadcast) _write_string(writer, "broadcast"); if (instrux->HasMask) _write_string(writer, "mask"); if (instrux->HasZero) _write_string(writer, "zero"); if (instrux->HasEr) _write_string(writer, "er"); if (instrux->HasSae) _write_string(writer, "sae"); if (instrux->SignDisp) _write_string(writer, "sign_disp"); _end_array(writer); } static void _write_access(Writer &writer, const char *key, const uint8_t access) { _start_array(writer, key); if (access & ND_ACCESS_READ) _write_string(writer, "read"); if (access & ND_ACCESS_WRITE) _write_string(writer, "write"); if (access & ND_ACCESS_COND_READ) _write_string(writer, "cond_read"); if (access & ND_ACCESS_COND_WRITE) _write_string(writer, "cond_write"); if (access == ND_ACCESS_NONE) _write_string(writer, "none"); _end_array(writer); } static void _start_write_default_op(Writer &writer, const ND_OPERAND &op) { _start_object(writer); _start_array(writer, "flags"); if (op.Flags.IsDefault) _write_string(writer, "default"); if (op.Flags.SignExtendedOp1) _write_string(writer, "sign_extended_op1"); if (op.Flags.SignExtendedDws) _write_string(writer, "sign_extended_dws"); _end_array(writer); _write_uint(writer, "size", op.Size); _write_uint(writer, "raw_size", op.RawSize); _write_access(writer, "access", op.Access.Access); _start_object(writer, "decorator"); if (op.Decorator.HasMask) _write_uint(writer, "mask", op.Decorator.Mask.Msk); // TODO: k0-k7 if (op.Decorator.HasZero) _write_bool(writer, "zeroing", true); if (op.Decorator.HasBroadcast) { _start_object(writer, "broadcast"); _write_uint(writer, "count", op.Decorator.Broadcast.Count); _write_uint(writer, "size", op.Decorator.Broadcast.Size); _end_object(writer); } if (op.Decorator.HasEr) _write_bool(writer, "er", true); if (op.Decorator.HasSae) _write_bool(writer, "sae", true); _end_object(writer); // "decorator" switch (op.Type) { case ND_OP_NOT_PRESENT: _write_string(writer, "type", "not_preset"); break; case ND_OP_REG: _write_string(writer, "type", "register"); break; case ND_OP_MEM: _write_string(writer, "type", "memory"); break; case ND_OP_IMM: _write_string(writer, "type", "immediate"); break; case ND_OP_OFFS: _write_string(writer, "type", "offset"); break; case ND_OP_ADDR: _write_string(writer, "type", "address"); break; case ND_OP_CONST: _write_string(writer, "type", "constant"); break; case ND_OP_BANK: _write_string(writer, "type", "bank"); break; default: _write_string(writer, "type", ""); break; } // returns without closing the object } static void _write_op_reg(Writer &writer, const ND_OPERAND &op) { const auto& reg = op.Info.Register; _write_uint(writer, "size", reg.Size); _write_string(writer, "reg_type", reg_type_to_str(reg.Type)); _write_string(writer, "reg", reg_to_str(reg.Reg, reg.Type)); _write_uint(writer, "reg_id", reg.Reg); _write_uint(writer, "count", reg.Count); if (reg.IsHigh8) _write_bool(writer, "is_high8", true); if (reg.IsBlock) _write_bool(writer, "is_block", true); } static void _write_op_mem(Writer &writer, const ND_OPERAND &op) { const auto& mem = op.Info.Memory; _start_array(writer, "flags"); if (mem.IsRipRel) _write_string(writer, "rip_rel"); if (mem.IsStack) _write_string(writer, "stack"); if (mem.IsString) _write_string(writer, "string"); if (mem.IsShadowStack) _write_string(writer, "shadow_stack"); if (mem.IsDirect) _write_string(writer, "direct"); if (mem.IsBitbase) _write_string(writer, "bitbase"); if (mem.IsAG) _write_string(writer, "ag"); if (mem.IsMib) _write_string(writer, "mib"); if (mem.HasBroadcast) _write_string(writer, "broadcast"); _end_array(writer); if (mem.IsVsib) { _start_object(writer, "vsib"); _write_uint(writer, "index_size", mem.Vsib.IndexSize); _write_uint(writer, "elem_size", mem.Vsib.ElemSize); _write_uint(writer, "elem_count", mem.Vsib.ElemCount); _end_object(writer); } if (mem.HasSeg) _write_uint(writer, "seg", mem.Seg); if (mem.HasBase) { _write_uint(writer, "base_size", mem.BaseSize); _write_uint(writer, "base", mem.Base); } if (mem.HasIndex) { _write_uint(writer, "index_size", mem.IndexSize); _write_uint(writer, "index", mem.Index); _write_uint(writer, "scale", mem.Scale); } if (mem.HasDisp || mem.HasCompDisp) { if (mem.HasDisp) _write_uint(writer, "disp_size", mem.DispSize); if (mem.HasCompDisp) _write_uint(writer, "comp_disp_size", mem.CompDispSize); _write_uint(writer, "disp", mem.Disp); } } static void _write_operands(Writer &writer, const INSTRUX *instrux) { _start_array(writer, "operands"); for (auto i = 0; i < instrux->OperandsCount; i++) { const auto& op = instrux->Operands[i]; _start_write_default_op(writer, op); _start_object(writer, "info"); switch (op.Type) { case ND_OP_REG: _write_op_reg(writer, op); break; case ND_OP_MEM: _write_op_mem(writer, op); break; case ND_OP_IMM: _write_uint64(writer, "imm", op.Info.Immediate.Imm); break; case ND_OP_OFFS: _write_uint64(writer, "rel", op.Info.RelativeOffset.Rel); break; case ND_OP_ADDR: _write_uint(writer, "base_seg", op.Info.Address.BaseSeg); _write_uint64(writer, "offset", op.Info.Address.Offset); break; case ND_OP_CONST: _write_uint64(writer, "const", op.Info.Constant.Const); break; case ND_OP_NOT_PRESENT: case ND_OP_BANK: break; } _end_object(writer); // "info" _end_object(writer); // the one from _start_write_default_op } _end_array(writer); } static void _write_valid_modes(Writer &writer, const ND_VALID_MODES &modes) { _start_array(writer, "valid_modes"); if (modes.Ring0) _write_string(writer, "ring0"); if (modes.Ring1) _write_string(writer, "ring1"); if (modes.Ring2) _write_string(writer, "ring2"); if (modes.Ring3) _write_string(writer, "ring3"); if (modes.Real) _write_string(writer, "real"); if (modes.V8086) _write_string(writer, "v8086"); if (modes.Protected) _write_string(writer, "protected"); if (modes.Compat) _write_string(writer, "compatibility"); if (modes.Long) _write_string(writer, "long"); if (modes.Smm) _write_string(writer, "smm"); if (modes.Sgx) _write_string(writer, "sgx"); if (modes.Tsx) _write_string(writer, "tsx"); if (modes.VmxRoot) _write_string(writer, "vmx_root"); if (modes.VmxNonRoot) _write_string(writer, "vmx_non_root"); if (modes.VmxOff) _write_string(writer, "vmx_off"); _end_array(writer); } static void _write_valid_prefixes(Writer &writer, const ND_VALID_PREFIXES &prefixes) { _start_array(writer, "valid_prefixes"); if (prefixes.Rep) _write_string(writer, "rep"); if (prefixes.RepCond) _write_string(writer, "rep_cond"); if (prefixes.Lock) _write_string(writer, "lock"); if (prefixes.Hle) _write_string(writer, "hle"); if (prefixes.Xacquire) _write_string(writer, "xacquire"); if (prefixes.Xrelease) _write_string(writer, "xrelease"); if (prefixes.Bnd) _write_string(writer, "bnd"); if (prefixes.Bhint) _write_string(writer, "bhint"); if (prefixes.HleNoLock) _write_string(writer, "hle_no_lock"); if (prefixes.Dnt) _write_string(writer, "dnt"); _end_array(writer); } static void _write_valid_decorators(Writer &writer, const ND_VALID_DECORATORS &decorators) { _start_array(writer, "valid_decorators"); if (decorators.Er) _write_string(writer, "er"); if (decorators.Sae) _write_string(writer, "Sae"); if (decorators.Zero) _write_string(writer, "Zero"); if (decorators.Mask) _write_string(writer, "mask"); if (decorators.Broadcast) _write_string(writer, "broadcast"); _end_array(writer); } static void _write_cpuid_flag(Writer &writer, const ND_CPUID_FLAG &cpuid_flag) { if (0 == cpuid_flag.Flag) return; _start_object(writer, "cpuid_flag"); _write_uint64(writer, "flag", cpuid_flag.Flag); _write_uint(writer, "leaf", cpuid_flag.Leaf); _write_uint(writer, "sub_leaf", static_cast(cpuid_flag.SubLeaf)); _write_uint(writer, "reg", static_cast(cpuid_flag.Reg)); _write_uint(writer, "bit", static_cast(cpuid_flag.Bit)); _end_object(writer); } static void _write_rflags(Writer &writer, const ND_RFLAGS &rflags, const char *key) { _start_array(writer, key); if (rflags.CF) _write_string(writer, "cf"); if (rflags.PF) _write_string(writer, "pf"); if (rflags.AF) _write_string(writer, "af"); if (rflags.ZF) _write_string(writer, "zf"); if (rflags.SF) _write_string(writer, "sf"); if (rflags.TF) _write_string(writer, "tf"); if (rflags.IF) _write_string(writer, "if"); if (rflags.DF) _write_string(writer, "df"); if (rflags.OF) _write_string(writer, "of"); if (rflags.IOPL) _write_string(writer, "iopl"); if (rflags.NT) _write_string(writer, "nt"); if (rflags.RF) _write_string(writer, "rf"); if (rflags.VM) _write_string(writer, "vm"); if (rflags.AC) _write_string(writer, "ac"); if (rflags.VIF) _write_string(writer, "vif"); if (rflags.VIP) _write_string(writer, "vip"); if (rflags.ID) _write_string(writer, "id"); _end_array(writer); } static void _write_flags_access(Writer &writer, INSTRUX *instrux) { if (ND_ACCESS_NONE == instrux->FlagsAccess.RegAccess) return; _start_object(writer, "flags_access"); _write_access(writer, "access", instrux->FlagsAccess.RegAccess); if ((instrux->FlagsAccess.RegAccess & ND_ACCESS_ANY_READ) && instrux->FlagsAccess.Tested.Raw) _write_rflags(writer, instrux->FlagsAccess.Tested, "tested"); if ((instrux->FlagsAccess.RegAccess & ND_ACCESS_ANY_WRITE) && instrux->FlagsAccess.Modified.Raw) _write_rflags(writer, instrux->FlagsAccess.Modified, "modified"); if (instrux->FlagsAccess.Set.Raw) _write_rflags(writer, instrux->FlagsAccess.Set, "set"); if (instrux->FlagsAccess.Cleared.Raw) _write_rflags(writer, instrux->FlagsAccess.Cleared, "cleared"); if (instrux->FlagsAccess.Undefined.Raw) _write_rflags(writer, instrux->FlagsAccess.Undefined, "undefined"); _end_object(writer); } StringBuffer instrux_to_json(INSTRUX *instrux, size_t rip, bool text_only /* = false */) { char text[ND_MIN_BUF_SIZE]; auto status = NdToText(instrux, rip, sizeof(text), text); if (!ND_SUCCESS(status)) text[0] = 0; auto s = StringBuffer {nullptr, 4096}; auto writer = Writer {s, nullptr}; _start_object(writer); _write_string(writer, "text", text); if (text_only) { _end_object(writer); return s; } _write_uint(writer, "def_code", _disasm_size_to_int(instrux->DefCode)); _write_uint(writer, "def_data", _disasm_size_to_int(instrux->DefData)); _write_uint(writer, "def_stack", _disasm_size_to_int(instrux->DefStack)); _write_string(writer, "enc_mode", enc_mode_to_str(instrux->EncMode)); _write_uint(writer, "addr_mode", _disasm_size_to_int(instrux->AddrMode)); _write_uint(writer, "op_mode", _disasm_size_to_int(instrux->OpMode)); _write_uint(writer, "ef_op_mode", _disasm_size_to_int(instrux->EfOpMode)); _write_uint(writer, "vec_mode", _disasm_size_to_int(instrux->VecMode) * 8); _write_uint(writer, "ef_vec_mnode", _disasm_size_to_int(instrux->EfVecMode) * 8); _write_rex(writer, instrux); _write_modrm(writer, instrux); _write_sib(writer, instrux); _write_drex(writer, instrux); _write_vex2(writer, instrux); _write_vex3(writer, instrux); _write_xop(writer, instrux); _write_evex(writer, instrux); if (instrux->Rep) _write_uint(writer, "rep", instrux->Rep); if (instrux->Seg) _write_uint(writer, "seg", instrux->Seg); _write_uint(writer, "stack_words", instrux->StackWords); _write_exs(writer, instrux); _write_prefixes(writer, instrux); _write_chunks(writer, instrux); if (instrux->IsRepeated) _write_bool(writer, "is_repeated", true); if (instrux->IsXacquireEnabled) _write_bool(writer, "is_xacquire_enabled", true); if (instrux->IsXreleaseEnabled) _write_bool(writer, "is_xrelease_enabled", true); if (instrux->IsRipRelative) _write_bool(writer, "is_rip_relative", true); if (instrux->IsCetTracked) _write_bool(writer, "is_cet_tracked", true); if (instrux->HasMandatory66) _write_bool(writer, "mandatory_66", true); if (instrux->HasMandatoryF2) _write_bool(writer, "mandatory_f2", true); if (instrux->HasMandatoryF3) _write_bool(writer, "mandatory_f3", true); _write_uint(writer, "length", instrux->Length); _write_uint(writer, "word_length", static_cast(instrux->WordLength)); _write_uint(writer, "pref_length", static_cast(instrux->PrefLength)); _start_object(writer, "address"); _write_uint(writer, "ip", instrux->Address.Ip); _write_uint(writer, "cs", instrux->Address.Cs); _end_object(writer); _write_uint(writer, "op_offset", static_cast(instrux->OpOffset)); _write_uint(writer, "main_op_offset", static_cast(instrux->MainOpOffset)); if (instrux->HasAddr) { _start_object(writer, "addr"); _write_uint(writer, "len", static_cast(instrux->AddrLength)); _write_uint(writer, "offset", static_cast(instrux->AddrOffset)); _end_object(writer); } if (instrux->HasMoffset) { _start_object(writer, "moffset"); _write_uint64(writer, "value", instrux->Moffset); _write_uint(writer, "len", static_cast(instrux->MoffsetLength)); _write_uint(writer, "offset", static_cast(instrux->MoffsetOffset)); _end_object(writer); }; if (instrux->HasDisp) { _start_object(writer, "displacement"); _write_uint(writer, "value", instrux->Displacement); _write_uint(writer, "len", static_cast(instrux->DispLength)); _write_uint(writer, "offset", static_cast(instrux->DispOffset)); _end_object(writer); } if (instrux->HasRelOffs) { _start_object(writer, "relative_offset"); _write_uint(writer, "value", instrux->RelativeOffset); _write_uint(writer, "len", static_cast(instrux->RelOffsLength)); _write_uint(writer, "offset", static_cast(instrux->RelOffsOffset)); _end_object(writer); } if (instrux->HasImm1) { _start_object(writer, "immediate1"); _write_uint64(writer, "value", instrux->Immediate1); _write_uint(writer, "len", static_cast(instrux->Imm1Length)); _write_uint(writer, "offset", static_cast(instrux->Imm1Offset)); _end_object(writer); } if (instrux->HasImm2) { _start_object(writer, "immediate2"); _write_uint(writer, "value", instrux->Immediate2); _write_uint(writer, "len", static_cast(instrux->Imm2Length)); _write_uint(writer, "offset", static_cast(instrux->Imm2Offset)); _end_object(writer); } if (instrux->HasImm3) { _start_object(writer, "immediate3"); _write_uint(writer, "value", instrux->Immediate3); _write_uint(writer, "len", static_cast(instrux->Imm3Length)); _write_uint(writer, "offset", static_cast(instrux->Imm3Offset)); _end_object(writer); } if (instrux->HasSseImm) { _start_object(writer, "sse_immediate"); _write_uint(writer, "value", instrux->SseImmediate); _write_uint(writer, "offset", static_cast(instrux->SseImmOffset)); _end_object(writer); } _write_uint(writer, "sse_condition", instrux->SseCondition); _write_uint(writer, "condition", instrux->Condition); _write_uint(writer, "operands_count", instrux->OperandsCount); _write_uint(writer, "exp_operands_count", instrux->ExpOperandsCount); _write_uint(writer, "operands_encoding_map", instrux->OperandsEncodingMap); _write_operands(writer, instrux); _write_access(writer, "rip_access", instrux->RipAccess); _write_access(writer, "memory_access", instrux->MemoryAccess); _write_access(writer, "stack_access", instrux->StackAccess); _write_flags_access(writer, instrux); _write_uint(writer, "attributes", instrux->Attributes); _write_string(writer, "class", ins_class_to_str(instrux->Iclass)); _write_string(writer, "category", ins_cat_to_str(instrux->Category)); _write_string(writer, "set", ins_set_to_str(instrux->IsaSet)); _write_cpuid_flag(writer, instrux->CpuidFlag); _write_valid_modes(writer, instrux->ValidModes); _write_valid_prefixes(writer, instrux->ValidPrefixes); _write_valid_decorators(writer, instrux->ValidDecorators); _write_string(writer, "mnemonic", instrux->Mnemonic); _start_array(writer, "opcode_bytes"); for (int i = 0; i < instrux->OpLength; i++) _write_uint(writer, instrux->OpCodeBytes[i]); _end_array(writer); _write_uint(writer, "primary_opcode", instrux->PrimaryOpCode); _start_array(writer, "bytes"); for (int i = 0; i < instrux->Length; i++) _write_uint(writer, instrux->InstructionBytes[i]); _end_array(writer); _end_object(writer); return s; } StringBuffer byte_to_json(uint8_t byte, size_t rip) { auto s = StringBuffer {nullptr, 64}; auto writer = Writer {s, nullptr}; _start_object(writer); _write_uint(writer, "byte", byte); _write_uint(writer, "length", 1); _write_uint64(writer, "rip", rip); _end_object(writer); return s; } const char *json_to_string(StringBuffer &j) { return j.GetString(); }