mirror of
https://github.com/Ed94/perfaware.git
synced 2026-09-14 03:39:23 +00:00
Runtime encode
This commit is contained in:
@@ -449,6 +449,9 @@ x8616_decode_one_plex(X8616_DecodePlex* plex)
|
||||
plex->instruction.d = (plan->flags & x8616_plan_has_d) ? plex->d : x8616_d_rm_dst;
|
||||
plex->instruction.w = (plan->flags & x8616_plan_has_w) ? plex->w : x8616_w_byte;
|
||||
plex->instruction.has_mod_rm = (plan->flags & x8616_plan_has_modrm) != 0;
|
||||
plex->instruction.header = plex->header;
|
||||
plex->instruction.mod_rm = plex->mod_rm;
|
||||
plex->instruction.post_opcode = plex->post_opcode;
|
||||
|
||||
U4 total_required = prefix_at + plex->body_required;
|
||||
U4 total_available = plex->source_size;
|
||||
|
||||
@@ -74,6 +74,9 @@ typedef Struct_(X8616_DecodedInstruction) {
|
||||
X8616_ALU alu;
|
||||
X8616_Condition cc;
|
||||
B1 has_mod_rm;
|
||||
U1 header;
|
||||
U1 mod_rm;
|
||||
U1 post_opcode;
|
||||
U1 size;
|
||||
U1 size_required;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
#ifdef INTELLISENSE_DIRECTIVES
|
||||
# include "encode.h"
|
||||
#endif
|
||||
|
||||
internal void
|
||||
x8616_encode_push(FArena_R arena, X8616_InfoList_R msgs, X8616_EncodeStatus status, U4 id, U2 size, U4 expected, U4 actual) {
|
||||
if (status == x8616_encode_ok || arena == 0) return;
|
||||
X8616_InfoKind kind = x8616_info_error;
|
||||
X8616_InfoCode code = x8616_info_encode_invalid_record;
|
||||
if (status == x8616_encode_output_full) code = x8616_info_encode_output_full;
|
||||
else if (status == x8616_encode_bad_request) code = x8616_info_encode_bad_request;
|
||||
x8616_info_push(arena, msgs, kind, code, id, size, expected, actual);
|
||||
}
|
||||
|
||||
FI_ void x8616_encode_buf_u1(U1* buf, U1_R n, U1 value) { buf[n[0]] = value; n[0] += 1; }
|
||||
FI_ void x8616_encode_buf_u2(U1* buf, U1_R n, U2 value) {
|
||||
x8616_encode_buf_u1(buf, n, u1_(value));
|
||||
x8616_encode_buf_u1(buf, n, u1_(value >> 8));
|
||||
}
|
||||
FI_ void x8616_encode_buf_disp(U1* buf, U1_R n, S2 value, U1 bytes) {
|
||||
if (bytes == 1) x8616_encode_buf_u1(buf, n, u1_(value));
|
||||
if (bytes == 2) x8616_encode_buf_u2(buf, n, u2_(value));
|
||||
}
|
||||
|
||||
internal X8616_EncodeStatus
|
||||
x8616_encode_instruction(Str8Gen_R gen, X8616_DecodedInstruction_R inst)
|
||||
{
|
||||
B4 bad = inst->decode_flags & (x8616_decode_invalid | x8616_decode_truncated);
|
||||
bad |= inst->size == 0;
|
||||
if (bad) return x8616_encode_invalid_record;
|
||||
U1 buf[16];
|
||||
U1 n = 0;
|
||||
U1 rep = inst->prefixes.repeat == x8616_rep ? x8616_rep_prefix() : x8616_repne_prefix();
|
||||
if (inst->prefixes.lock) { x8616_encode_buf_u1(buf, & n, x8616_lock_prefix()); }
|
||||
if (inst->prefixes.has_repeat) { x8616_encode_buf_u1(buf, & n, rep); }
|
||||
if (inst->prefixes.has_segment) { x8616_encode_buf_u1(buf, & n, x8616_segment_prefix(inst->prefixes.segment)); }
|
||||
x8616_encode_buf_u1(buf, & n, inst->header);
|
||||
if (inst->post_opcode) { x8616_encode_buf_u1(buf, & n, inst->post_opcode); }
|
||||
if (inst->has_mod_rm) { x8616_encode_buf_u1(buf, & n, inst->mod_rm); }
|
||||
|
||||
for (U1 id = 0; id < inst->operand_count; ++id) {
|
||||
X8616_DecodedOperand_R op = inst->operands + id;
|
||||
if ((op->flags & x8616_decoded_operand_memory) == 0) continue;
|
||||
if ( op->flags & x8616_decoded_operand_direct) x8616_encode_buf_u2(buf, & n, op->address);
|
||||
else x8616_encode_buf_disp(buf, & n, op->displacement, op->displacement_bytes);
|
||||
}
|
||||
for (U1 id = 0; id < inst->operand_count; ++id) {
|
||||
X8616_DecodedOperand_R op = inst->operands + id;
|
||||
B4 op_rel = op->flags & x8616_decoded_operand_relative;
|
||||
B4 op_imm = (op->flags & x8616_decoded_operand_immediate) && op->immediate_bytes;
|
||||
B4 op_far = op->flags & x8616_decoded_operand_far_ptr;
|
||||
if (op_rel) { x8616_encode_buf_disp(buf, & n, op->displacement, op->displacement_bytes); }
|
||||
else if (op_imm) { x8616_encode_buf_disp(buf, & n, s2_(op->immediate), op->immediate_bytes); }
|
||||
else if (op_far) {
|
||||
x8616_encode_buf_u2(buf, & n, op->far_offset);
|
||||
x8616_encode_buf_u2(buf, & n, op->far_segment);
|
||||
}
|
||||
}
|
||||
|
||||
if (n > gen->cap - gen->len) return x8616_encode_output_full;
|
||||
mem_copy(u8_(gen->ptr + gen->len), u8_(buf), n);
|
||||
gen->len += n;
|
||||
return x8616_encode_ok;
|
||||
}
|
||||
|
||||
X8616_EncodeInfo x8616_encode_instructions(X8616_EncodeRequest request)
|
||||
{
|
||||
X8616_EncodeInfo result = {0};
|
||||
X8616_InfoList local = {0};
|
||||
X8616_InfoList_R msgs = request.msgs ? request.msgs : & local;
|
||||
Str8Gen gen = {0};
|
||||
|
||||
B4 bad =
|
||||
(request.instruction_count && request.instructions == 0)
|
||||
|| (request.output.len && request.output.ptr == 0)
|
||||
|| (request.info_arena == 0);
|
||||
if (bad) {
|
||||
if (request.info_arena) {
|
||||
x8616_encode_push(request.info_arena, msgs, x8616_encode_bad_request, 0, 0, 0, 0);
|
||||
}
|
||||
goto exit;
|
||||
}
|
||||
|
||||
gen = str8gen_make(request.output);
|
||||
result.bytes.ptr = u8_(gen.ptr);
|
||||
|
||||
for (U4 id = 0; id < request.instruction_count; ++id)
|
||||
{
|
||||
X8616_DecodedInstruction_R inst = & request.instructions[id];
|
||||
U8 at = gen.len;
|
||||
X8616_EncodeStatus st = x8616_encode_instruction(& gen, inst);
|
||||
if (st == x8616_encode_invalid_record) {
|
||||
gen.len = at;
|
||||
x8616_encode_push(request.info_arena, msgs, st, id, inst->size, 0, u4_(inst->op));
|
||||
continue;
|
||||
}
|
||||
if (st == x8616_encode_output_full) {
|
||||
gen.len = at;
|
||||
x8616_encode_push(request.info_arena, msgs, st
|
||||
, id, inst->size, u4_(request.output.len), u4_(at));
|
||||
goto exit;
|
||||
}
|
||||
result.instructions_written += 1;
|
||||
}
|
||||
|
||||
exit:
|
||||
result.bytes.len = gen.len;
|
||||
result.msgs = *msgs;
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#ifdef INTELLISENSE_DIRECTIVES
|
||||
# pragma once
|
||||
# include "decoder.h"
|
||||
#endif
|
||||
|
||||
typedef Enum_(U1, X8616_EncodeStatus) {
|
||||
x8616_encode_ok = 0x00,
|
||||
x8616_encode_output_full = 0x01,
|
||||
x8616_encode_invalid_record = 0x02,
|
||||
x8616_encode_bad_request = 0x03,
|
||||
};
|
||||
|
||||
typedef Struct_(X8616_EncodeRequest) {
|
||||
X8616_DecodedInstruction* instructions;
|
||||
U4 instruction_count; byte_pad(4);
|
||||
Slice output;
|
||||
FArena* info_arena;
|
||||
X8616_InfoList_R msgs;
|
||||
};
|
||||
|
||||
typedef Struct_(X8616_EncodeInfo) {
|
||||
X8616_InfoList msgs;
|
||||
Slice bytes;
|
||||
U4 instructions_written;
|
||||
byte_pad(4);
|
||||
};
|
||||
|
||||
X8616_EncodeInfo x8616_encode_instructions(X8616_EncodeRequest request);
|
||||
@@ -38,6 +38,10 @@ typedef Enum_(U1, X8616_InfoCode) {
|
||||
x8616_info_parse_invalid_record = 0x13,
|
||||
x8616_info_parse_unsupported_form = 0x14,
|
||||
|
||||
x8616_info_encode_bad_request = 0x15,
|
||||
x8616_info_encode_invalid_record = 0x16,
|
||||
x8616_info_encode_output_full = 0x17,
|
||||
|
||||
x8616_info_count,
|
||||
};
|
||||
|
||||
@@ -78,6 +82,9 @@ RO_ global Str8 x8616_info_templates[x8616_info_count] = {
|
||||
[x8616_info_parse_output_full] = slit8("Parse output is full: capacity <expected>, produced <actual>."),
|
||||
[x8616_info_parse_invalid_record] = slit8("Parse record at <offset> is not a valid instruction (op <actual>)."),
|
||||
[x8616_info_parse_unsupported_form] = slit8("Parse record at <offset> has an unsupported form (op <actual>)."),
|
||||
[x8616_info_encode_bad_request] = slit8("Encode request is missing instructions, output, or info arena."),
|
||||
[x8616_info_encode_invalid_record] = slit8("Encode record <offset> is invalid or truncated (op <actual>)."),
|
||||
[x8616_info_encode_output_full] = slit8("Encode output is full at record <offset>: capacity <expected>, produced <actual>."),
|
||||
};
|
||||
|
||||
typedef Struct_(X8616_InfoList) {
|
||||
@@ -120,3 +127,15 @@ FI_ void x8616_info_push(FArena_R scratch
|
||||
msg->text = x8616_info_template(code);
|
||||
sll_queue_push_n(msgs->first, msgs->last, msg, next);
|
||||
}
|
||||
|
||||
typedef Struct_(X8616_InfoTextValues) { Str8 offset; Str8 expected; Str8 actual; };
|
||||
|
||||
FI_ Str8
|
||||
x8616_info_render(Slice output, X8616_InfoMsg_R msg, X8616_InfoTextValues values) {
|
||||
KTL_Slot_Str8 slots[] = {
|
||||
{ ktl_str8_key("offset"), values.offset },
|
||||
{ ktl_str8_key("expected"), values.expected },
|
||||
{ ktl_str8_key("actual"), values.actual },
|
||||
};
|
||||
return str8_fmt_ktl_buf(output, ktl_str8_from_arr(slots), msg->text);
|
||||
}
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
#ifdef INTELLISENSE_DIRECTIVES
|
||||
# pragma once
|
||||
# include "duffle/tables.h"
|
||||
# include "duffle/text.h"
|
||||
# include "info.h"
|
||||
#endif
|
||||
|
||||
typedef Struct_(X8616_InfoTextValues) { Str8 offset; Str8 expected; Str8 actual; };
|
||||
|
||||
FI_ Str8
|
||||
x8616_info_render(Slice output, X8616_InfoMsg_R msg, X8616_InfoTextValues values) {
|
||||
KTL_Slot_Str8 slots[] = {
|
||||
{ ktl_str8_key("offset"), values.offset },
|
||||
{ ktl_str8_key("expected"), values.expected },
|
||||
{ ktl_str8_key("actual"), values.actual },
|
||||
};
|
||||
return str8_fmt_ktl_buf(output, ktl_str8_from_arr(slots), msg->text);
|
||||
}
|
||||
Reference in New Issue
Block a user