From ce4d09d431c96977ea5f8a142b7b479eeee8fb49 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Wed, 17 Dec 2025 17:32:03 -0800 Subject: [PATCH] WIP DW_OP_piece --- src/dwarf/dwarf.h | 4 +- src/dwarf/dwarf_expr.c | 107 +++++++++++++++++++++++++++++++++-------- src/dwarf/dwarf_expr.h | 16 ++---- src/torture/torture.c | 35 ++++++++++++++ 4 files changed, 128 insertions(+), 34 deletions(-) diff --git a/src/dwarf/dwarf.h b/src/dwarf/dwarf.h index 9f3b0dfc..a5ac02f0 100644 --- a/src/dwarf/dwarf.h +++ b/src/dwarf/dwarf.h @@ -1548,7 +1548,7 @@ typedef enum X(RegX, 0x90, 1, 0, 1, ULEB128, Null) \ X(FBReg, 0x91, 1, 0, 1, SLEB128, Null) \ X(BRegX, 0x92, 2, 0, 1, ULEB128, SLEB128) \ - X(Piece, 0x93, 1, 0, 0, ULEB128, Null) \ + X(Piece, 0x93, 1, 1, 0, ULEB128, Null) \ X(DerefSize, 0x94, 1, 1, 1, U8, Null) \ X(XDerefSize, 0x95, 1, 2, 1, U8, Null) \ X(Nop, 0x96, 0, 0, 0, Null, Null) \ @@ -1558,7 +1558,7 @@ typedef enum X(CallRef, 0x9a, 1, 0, 0, DwarfUInt,Null) \ X(FormTlsAddress, 0x9b, 0, 0, 1, Null, Null) \ X(CallFrameCfa, 0x9c, 0, 0, 1, Null, Null) \ - X(BitPiece, 0x9d, 2, 0, 0, ULEB128, ULEB128) + X(BitPiece, 0x9d, 2, 1, 0, ULEB128, ULEB128) #define DW_Expr_V4_XList \ X(ImplicitValue, 0x9e, 2, 0, 1, Block, Null) \ diff --git a/src/dwarf/dwarf_expr.c b/src/dwarf/dwarf_expr.c index 89087294..04f9e1ba 100644 --- a/src/dwarf/dwarf_expr.c +++ b/src/dwarf/dwarf_expr.c @@ -1269,29 +1269,44 @@ dw_eval_expr(Arena *arena, } break; case DW_ExprOp_Piece: { - if (stack->count) { - String8 value = dw_string_from_expr_value(arena, arch, dw_expr_stack_pop(stack)); - if (inst->operands[0].u64 <= value.size) { - dw_piece_list_push(arena, &pieces, (DW_Piece){ .kind = DW_PieceKind_Value, .value = { .ptr = value.str, .bit_size = inst->operands[0].u64 * 8 }}); - } else { - Assert(0 && "out of bounds size in the piece opcode"); - goto exit; - } + B32 is_undefined = stack->count == 0 || (inst->prev && inst->prev->opcode == DW_ExprOp_Piece); + if (is_undefined) { + dw_piece_list_push(arena, &pieces, (DW_Piece){ .kind = DW_PieceKind_Undefined, .bit_size = inst->operands[0].u64 * 8 }); } else { - dw_piece_list_push(arena, &pieces, (DW_Piece){ .kind = DW_PieceKind_Undefined, .undef_bit_size = inst->operands[0].u64 * 8 }); + DW_ExprValue top = dw_expr_stack_pop(stack); + + String8 value; + + // piece is a memory reference + if (top.type == DW_ExprValueType_Addr) { + U64 value_size = inst->operands[0].u64; + U8 *value_buffer = push_array(arena, U8, value_size); + MachineOpResult read_result = mem_read(top.addr, value_buffer, value_size, mem_read_ud); + if (read_result != MachineOpResult_Ok) { Assert(0 && "failed to read piece memory referece"); goto exit; } + } + // piece is a value + else { + value = dw_string_from_expr_value(arena, arch, top); + } + + if (inst->operands[0].u64 > value.size) { Assert(0 && "out of bounds size in the piece opcode"); goto exit; } + dw_piece_list_push(arena, &pieces, (DW_Piece){ .kind = DW_PieceKind_Value, .bit_size = inst->operands[0].u64 * 8, .value = value.str }); } } break; + case DW_ExprOp_BitPiece: { - if (stack->count) { - String8 value = dw_string_from_expr_value(arena, arch, dw_expr_stack_pop(stack)); - if (inst->operands[0].u64 <= value.size * 8) { - dw_piece_list_push(arena, &pieces, (DW_Piece){ .kind = DW_PieceKind_Value, .value = { .ptr = value.str, .bit_size = inst->operands[0].u64 }}); - } else { - Assert(0 && "out of bounds size in the bit piece opcode"); - goto exit; - } + B32 is_undefined = stack->count == 0 || (inst->prev && inst->prev->opcode == DW_ExprOp_Piece); + if (is_undefined) { + dw_piece_list_push(arena, &pieces, (DW_Piece){ .kind = DW_PieceKind_Undefined, .bit_size = inst->operands[0].u64 }); } else { - dw_piece_list_push(arena, &pieces, (DW_Piece){ .kind = DW_PieceKind_Undefined, .undef_bit_size = inst->operands[0].u64 }); + String8 value; + if (dw_expr_stack_peek(stack).type == DW_ExprValueType_Addr) { + NotImplemented; + } else { + value = dw_string_from_expr_value(arena, arch, dw_expr_stack_pop(stack)); + } + if (inst->operands[0].u64 > value.size * 8) { Assert(0 && "out of bounds size in piece opcode"); goto exit; } + dw_piece_list_push(arena, &pieces, (DW_Piece){ .kind = DW_PieceKind_Value, .bit_size = inst->operands[0].u64, .value = value.str }); } } break; @@ -1485,8 +1500,60 @@ dw_eval_expr(Arena *arena, } } - if (stack->top) { - *value_out = stack->top->v; + // composite value + if (pieces.count > 0) { +#if 0 + U64 total_bit_size = 0; + for EachNode (n, DW_PieceNode, pieces.first) { + total_bit_size += n->v.bit_size; + } + + U64 value_size = CeilIntegerDiv(total_bit_size, 8); + U8 *value = push_array(arena, U8, value_size); + Rng1U64 *ranges = push_array(arena, Rng1U64, pieces.count); + U64 *offsets = push_array(arena, U64, pieces.count); + U64 value_idx = 0; + U64 value_cursor = 0; + U64 piece_cursor = 0; + for EachNode(n, DW_PieceNode, pieces.first) { + if (n->v.kind == DW_PieceKind_Value) { + ranges[value_idx] = r1u64(piece_cursor, piece_cursor + n->v.bit_size); + offsets[value_idx] = value_cursor; + for (U64 i = 0; i < n->v.bit_size; i += 8) { + U64 to_copy = Min(8, n->v.bit_size - i); + if (value_cursor % 8 == 0) { + value[value_cursor / 8] = n->v.value[i]; + } else { + value[value_cursor / 8] |= n->v.value[i] << (value_cursor % 8); + value[AlignPow2(value_cursor / 8, 8)] |= n->v.value[i] >> (value_cursor % 8); + } + value_cursor += to_copy; + } + value_idx += 1; + } + piece_cursor += n->v.bit_size; + } + + value_out->type = DW_ExprValueType_Generic; + value_out->ranges = (Rng1U64Array){ .count = pieces.count, .v = ranges }; + value_out->offsets = offsets; + value_out->generic = str8(value, value_size); +#else + NotImplemented; +#endif + } + // scalar + else { + if (stack->top) { + *value_out = stack->top->v; + + Rng1U64 *range = push_array(arena, Rng1U64, 1); + *range = r1u64(0, max_U64); + value_out->ranges = (Rng1U64Array){ .count = 1, .v = range }; + value_out->offsets = push_array(arena, U64, 1); + } else { + MemoryZeroStruct(value_out); + } } result = DW_ExprEvalResult_Ok; diff --git a/src/dwarf/dwarf_expr.h b/src/dwarf/dwarf_expr.h index 278481b1..4cc52f8b 100644 --- a/src/dwarf/dwarf_expr.h +++ b/src/dwarf/dwarf_expr.h @@ -40,6 +40,8 @@ typedef S8 DW_ExprBool; typedef struct DW_ExprValue { DW_ExprValueType type; + Rng1U64Array ranges; + U64 *offsets; union { U8 u8; U16 u16; @@ -77,13 +79,8 @@ typedef enum typedef struct DW_Piece { DW_PieceKind kind; - union { - U64 undef_bit_size; - struct { - U64 bit_size; - void *ptr; - } value; - }; + U64 bit_size; + U8 *value; } DW_Piece; typedef struct DW_PieceNode @@ -105,11 +102,6 @@ typedef struct DW_ExprStack DW_ExprValueNode *top; } DW_ExprStack; -typedef struct DW_ExprResult -{ - int x; -} DW_ExprResult; - typedef enum { DW_ExprEvalResult_Fail, diff --git a/src/torture/torture.c b/src/torture/torture.c index 2a9690cd..ff7d7a22 100644 --- a/src/torture/torture.c +++ b/src/torture/torture.c @@ -5163,6 +5163,40 @@ t_plus_uconst(void) return result; } +internal T_Result +t_reg_split_spill(void) +{ + Temp scratch = scratch_begin(0, 0); + T_Result result = T_Result_Fail; + + // setup register context + REGS_RegBlockX64 regs = {0}; + { + REGS_RegCode reg_code = reg_code_from_dw_reg(Arch_x64, DW_ExprOp_BReg3 - DW_ExprOp_BReg0); + Rng1U64 reg_range = regs_range_from_code(Arch_x64, 0, reg_code); + U64 value = 0xaaaa; + MemoryCopy((U8 *)®s + reg_range.min, &value, sizeof(value)); + } + { + REGS_RegCode reg_code = reg_code_from_dw_reg(Arch_x64, DW_ExprOp_BReg10 - DW_ExprOp_BReg0); + Rng1U64 reg_range = regs_range_from_code(Arch_x64, 0, reg_code); + U64 value = 0xbbbb; + MemoryCopy((U8 *)®s + reg_range.min, &value, sizeof(value)); + } + + DW_ExprEnc expr_encs[] = { DW_ExprEnc_Op(Reg3), DW_ExprEnc_Op(Piece), DW_ExprEnc_ULEB128(4), DW_ExprEnc_Op(Reg10), DW_ExprEnc_Op(Piece), DW_ExprEnc_ULEB128(2) }; + String8 expr_data = dw_encode_expr(scratch.arena, Arch_x64, DW_Format_64Bit, expr_encs, ArrayCount(expr_encs)); + DW_Expr expr = dw_expr_from_data(scratch.arena, DW_Format_64Bit, byte_size_from_arch(Arch_x64), expr_data); + + DW_ExprValue expr_value; + DW_ExprEvalResult expr_eval = dw_eval_expr(scratch.arena, Arch_x64, DW_Format_64Bit, 0, 0, 0, max_U64, expr, regs_read_dwarf_x64, ®s, 0, 0, &expr_value); + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + //////////////////////////////////////////////////////////////// internal void @@ -5251,6 +5285,7 @@ entry_point(CmdLine *cmdline) T(frame_relative_variable), T(call_by_reference), T(plus_uconst), + //T(reg_split_spill), #undef T };