From c894ac09a31380319ba9cfdc82025fcc614a8cc0 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Sun, 24 Nov 2024 04:11:52 -0500 Subject: [PATCH] dwarf: fix stepping through an inline loop containing one statement Previously, stepping from the single statement within the loop would always exit the loop because all of the code unrolled from the loop is associated with the same line and treated by the debugger as one line. --- lib/std/zig/AstGen.zig | 33 ++- lib/std/zig/Zir.zig | 3 + src/Air.zig | 4 + src/Air/types_resolved.zig | 1 + src/Liveness.zig | 2 + src/Liveness/Verify.zig | 1 + src/Sema.zig | 10 + src/arch/aarch64/CodeGen.zig | 1 + src/arch/arm/CodeGen.zig | 1 + src/arch/riscv64/CodeGen.zig | 1 + src/arch/sparc64/CodeGen.zig | 1 + src/arch/wasm/CodeGen.zig | 1 + src/arch/x86_64/CodeGen.zig | 41 ++-- src/arch/x86_64/Emit.zig | 392 ++++++++++++++++---------------- src/arch/x86_64/Lower.zig | 1 + src/arch/x86_64/Mir.zig | 5 +- src/codegen/c.zig | 6 + src/codegen/llvm.zig | 7 + src/dev.zig | 2 + src/link/Dwarf.zig | 5 + src/link/Elf/ZigObject.zig | 2 +- src/main.zig | 1 + src/print_air.zig | 1 + src/print_zir.zig | 2 + test/src/Debugger.zig | 418 +++++++++++++++++++++++++++++++++++ 25 files changed, 721 insertions(+), 221 deletions(-) diff --git a/lib/std/zig/AstGen.zig b/lib/std/zig/AstGen.zig index abec1f354a..a9b518357b 100644 --- a/lib/std/zig/AstGen.zig +++ b/lib/std/zig/AstGen.zig @@ -6024,7 +6024,7 @@ fn tryExpr( if (!parent_gz.is_comptime) { try emitDbgNode(parent_gz, node); } - const try_lc = LineColumn{ astgen.source_line - parent_gz.decl_line, astgen.source_column }; + const try_lc: LineColumn = .{ astgen.source_line - parent_gz.decl_line, astgen.source_column }; const operand_rl: ResultInfo.Loc, const block_tag: Zir.Inst.Tag = switch (ri.rl) { .ref => .{ .ref, .try_ptr }, @@ -6577,6 +6577,7 @@ fn whileExpr( const astgen = parent_gz.astgen; const tree = astgen.tree; const token_tags = tree.tokens.items(.tag); + const token_starts = tree.tokens.items(.start); const need_rl = astgen.nodes_need_rl.contains(node); const block_ri: ResultInfo = if (need_rl) ri else .{ @@ -6774,6 +6775,16 @@ fn whileExpr( try checkUsed(parent_gz, &then_scope.base, then_sub_scope); const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break"; if (!continue_scope.endsWithNoReturn()) { + astgen.advanceSourceCursor(token_starts[tree.lastToken(then_node)]); + try emitDbgStmt(parent_gz, .{ astgen.source_line - parent_gz.decl_line, astgen.source_column }); + _ = try parent_gz.add(.{ + .tag = .extended, + .data = .{ .extended = .{ + .opcode = .dbg_empty_stmt, + .small = undefined, + .operand = undefined, + } }, + }); _ = try continue_scope.addBreak(break_tag, continue_block, .void_value); } try continue_scope.setBlockBody(continue_block); @@ -6882,6 +6893,7 @@ fn forExpr( } const tree = astgen.tree; const token_tags = tree.tokens.items(.tag); + const token_starts = tree.tokens.items(.start); const node_tags = tree.nodes.items(.tag); const node_data = tree.nodes.items(.data); const gpa = astgen.gpa; @@ -7087,8 +7099,18 @@ fn forExpr( try checkUsed(parent_gz, &then_scope.base, then_sub_scope); - const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break"; + astgen.advanceSourceCursor(token_starts[tree.lastToken(then_node)]); + try emitDbgStmt(parent_gz, .{ astgen.source_line - parent_gz.decl_line, astgen.source_column }); + _ = try parent_gz.add(.{ + .tag = .extended, + .data = .{ .extended = .{ + .opcode = .dbg_empty_stmt, + .small = undefined, + .operand = undefined, + } }, + }); + const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break"; _ = try then_scope.addBreak(break_tag, cond_block, .void_value); var else_scope = parent_gz.makeSubBlock(&cond_scope.base); @@ -7135,6 +7157,7 @@ fn forExpr( .lhs = index_ptr, .rhs = index_plus_one, }); + const repeat_tag: Zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat; _ = try loop_scope.addNode(repeat_tag, node); @@ -7279,7 +7302,7 @@ fn switchExprErrUnion( }; astgen.advanceSourceCursorToNode(operand_node); - const operand_lc = LineColumn{ astgen.source_line - parent_gz.decl_line, astgen.source_column }; + const operand_lc: LineColumn = .{ astgen.source_line - parent_gz.decl_line, astgen.source_column }; const raw_operand = try reachableExpr(parent_gz, scope, operand_ri, operand_node, switch_node); const item_ri: ResultInfo = .{ .rl = .none }; @@ -7868,7 +7891,7 @@ fn switchExpr( const operand_ri: ResultInfo = .{ .rl = if (any_payload_is_ref) .ref else .none }; astgen.advanceSourceCursorToNode(operand_node); - const operand_lc = LineColumn{ astgen.source_line - parent_gz.decl_line, astgen.source_column }; + const operand_lc: LineColumn = .{ astgen.source_line - parent_gz.decl_line, astgen.source_column }; const raw_operand = try expr(parent_gz, scope, operand_ri, operand_node); const item_ri: ResultInfo = .{ .rl = .none }; @@ -8214,7 +8237,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref if (!gz.is_comptime) { try emitDbgNode(gz, node); } - const ret_lc = LineColumn{ astgen.source_line - gz.decl_line, astgen.source_column }; + const ret_lc: LineColumn = .{ astgen.source_line - gz.decl_line, astgen.source_column }; const defer_outer = &astgen.fn_block.?.base; diff --git a/lib/std/zig/Zir.zig b/lib/std/zig/Zir.zig index 00a48e21f7..f2c103f835 100644 --- a/lib/std/zig/Zir.zig +++ b/lib/std/zig/Zir.zig @@ -2088,6 +2088,8 @@ pub const Inst = struct { /// `operand` is `Zir.Inst.Ref` of the loaded LHS (*not* its type). /// `small` is an `Inst.InplaceOp`. inplace_arith_result_ty, + /// Marks a statement that can be stepped to but produces no code. + dbg_empty_stmt, pub const InstData = struct { opcode: Extended, @@ -4062,6 +4064,7 @@ fn findDeclsInner( .branch_hint, .inplace_arith_result_ty, .tuple_decl, + .dbg_empty_stmt, => return, // `@TypeOf` has a body. diff --git a/src/Air.zig b/src/Air.zig index 3aa5f317c0..4589bb1557 100644 --- a/src/Air.zig +++ b/src/Air.zig @@ -460,6 +460,8 @@ pub const Inst = struct { /// Result type is always void. /// Uses the `dbg_stmt` field. dbg_stmt, + /// Marks a statement that can be stepped to but produces no code. + dbg_empty_stmt, /// A block that represents an inlined function call. /// Uses the `ty_pl` field. Payload is `DbgInlineBlock`. dbg_inline_block, @@ -1468,6 +1470,7 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool) .breakpoint, .dbg_stmt, + .dbg_empty_stmt, .dbg_var_ptr, .dbg_var_val, .dbg_arg_inline, @@ -1629,6 +1632,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool { .try_ptr, .try_ptr_cold, .dbg_stmt, + .dbg_empty_stmt, .dbg_inline_block, .dbg_var_ptr, .dbg_var_val, diff --git a/src/Air/types_resolved.zig b/src/Air/types_resolved.zig index 098cb29b22..cc866184e4 100644 --- a/src/Air/types_resolved.zig +++ b/src/Air/types_resolved.zig @@ -417,6 +417,7 @@ fn checkBody(air: Air, body: []const Air.Inst.Index, zcu: *Zcu) bool { .work_group_size, .work_group_id, .dbg_stmt, + .dbg_empty_stmt, .err_return_trace, .save_err_return_trace_index, .repeat, diff --git a/src/Liveness.zig b/src/Liveness.zig index b5bffc6a48..709844c0ac 100644 --- a/src/Liveness.zig +++ b/src/Liveness.zig @@ -334,6 +334,7 @@ pub fn categorizeOperand( .repeat, .switch_dispatch, .dbg_stmt, + .dbg_empty_stmt, .unreach, .ret_addr, .frame_addr, @@ -973,6 +974,7 @@ fn analyzeInst( .ret_ptr, .breakpoint, .dbg_stmt, + .dbg_empty_stmt, .ret_addr, .frame_addr, .wasm_memory_size, diff --git a/src/Liveness/Verify.zig b/src/Liveness/Verify.zig index aa2239793a..01e0842ded 100644 --- a/src/Liveness/Verify.zig +++ b/src/Liveness/Verify.zig @@ -56,6 +56,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { .ret_ptr, .breakpoint, .dbg_stmt, + .dbg_empty_stmt, .ret_addr, .frame_addr, .wasm_memory_size, diff --git a/src/Sema.zig b/src/Sema.zig index 25fb54dab8..5acd2012d5 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -1355,6 +1355,11 @@ fn analyzeBodyInner( .field_parent_ptr => try sema.zirFieldParentPtr(block, extended), .builtin_value => try sema.zirBuiltinValue(block, extended), .inplace_arith_result_ty => try sema.zirInplaceArithResultTy(extended), + .dbg_empty_stmt => { + try sema.zirDbgEmptyStmt(block, inst); + i += 1; + continue; + }, }; }, @@ -6671,6 +6676,11 @@ fn zirDbgStmt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!voi }); } +fn zirDbgEmptyStmt(_: *Sema, block: *Block, _: Zir.Inst.Index) CompileError!void { + if (block.is_comptime or block.ownerModule().strip) return; + _ = try block.addNoOp(.dbg_empty_stmt); +} + fn zirDbgVar( sema: *Sema, block: *Block, diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 6371cf92f3..8fd27d4bb7 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -800,6 +800,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .try_ptr_cold => try self.airTryPtr(inst), .dbg_stmt => try self.airDbgStmt(inst), + .dbg_empty_stmt => self.finishAirBookkeeping(), .dbg_inline_block => try self.airDbgInlineBlock(inst), .dbg_var_ptr, .dbg_var_val, diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 9966648759..065f4a047d 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -787,6 +787,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .try_ptr_cold => try self.airTryPtr(inst), .dbg_stmt => try self.airDbgStmt(inst), + .dbg_empty_stmt => self.finishAirBookkeeping(), .dbg_inline_block => try self.airDbgInlineBlock(inst), .dbg_var_ptr, .dbg_var_val, diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index 24497defa2..29a0a8b8b5 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -1593,6 +1593,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { .frame_addr => try func.airFrameAddress(inst), .cond_br => try func.airCondBr(inst), .dbg_stmt => try func.airDbgStmt(inst), + .dbg_empty_stmt => func.finishAirBookkeeping(), .fptrunc => try func.airFptrunc(inst), .fpext => try func.airFpext(inst), .intcast => try func.airIntCast(inst), diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index a1bef1f4cd..7bbed29d8f 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -642,6 +642,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .try_ptr_cold => @panic("TODO try self.airTryPtrCold(inst)"), .dbg_stmt => try self.airDbgStmt(inst), + .dbg_empty_stmt => self.finishAirBookkeeping(), .dbg_inline_block => try self.airDbgInlineBlock(inst), .dbg_var_ptr, .dbg_var_val, diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 50a8869282..ccdf38a474 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -1924,6 +1924,7 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { .try_ptr_cold => func.airTryPtr(inst), .dbg_stmt => func.airDbgStmt(inst), + .dbg_empty_stmt => try func.finishAir(inst, .none, &.{}), .dbg_inline_block => func.airDbgInlineBlock(inst), .dbg_var_ptr => func.airDbgVar(inst, .local_var, true), .dbg_var_val => func.airDbgVar(inst, .local_var, false), diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 06ae399f25..298b2e11e0 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -961,9 +961,16 @@ pub fn generate( }, .debug_output = debug_output, .code = code, + .prev_di_loc = .{ + .line = func.lbrace_line, + .column = func.lbrace_column, + .is_stmt = switch (debug_output) { + .dwarf => |dwarf| dwarf.dwarf.debug_line.header.default_is_stmt, + .plan9 => undefined, + .none => undefined, + }, + }, .prev_di_pc = 0, - .prev_di_line = func.lbrace_line, - .prev_di_column = func.lbrace_column, }; defer emit.deinit(); emit.emitMir() catch |err| switch (err) { @@ -1066,9 +1073,8 @@ pub fn generateLazy( }, .debug_output = debug_output, .code = code, + .prev_di_loc = undefined, // no debug info yet .prev_di_pc = undefined, // no debug info yet - .prev_di_line = undefined, // no debug info yet - .prev_di_column = undefined, // no debug info yet }; defer emit.deinit(); emit.emitMir() catch |err| switch (err) { @@ -1194,13 +1200,16 @@ fn formatWipMir( switch (mir_inst.ops) { else => unreachable, .pseudo_dbg_prologue_end_none, - .pseudo_dbg_line_line_column, .pseudo_dbg_epilogue_begin_none, .pseudo_dbg_enter_block_none, .pseudo_dbg_leave_block_none, .pseudo_dbg_var_args_none, .pseudo_dead_none, => {}, + .pseudo_dbg_line_stmt_line_column, .pseudo_dbg_line_line_column => try writer.print( + " {[line]d}, {[column]d}", + mir_inst.data.line_column, + ), .pseudo_dbg_enter_inline_func, .pseudo_dbg_leave_inline_func => try writer.print(" {}", .{ ip.getNav(ip.indexToKey(mir_inst.data.func).func.owner_nav).name.fmt(ip), }), @@ -1281,14 +1290,7 @@ fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index { try self.mir_instructions.ensureUnusedCapacity(gpa, 1); const result_index: Mir.Inst.Index = @intCast(self.mir_instructions.len); self.mir_instructions.appendAssumeCapacity(inst); - if (inst.tag != .pseudo or switch (inst.ops) { - else => true, - .pseudo_dbg_prologue_end_none, - .pseudo_dbg_line_line_column, - .pseudo_dbg_epilogue_begin_none, - .pseudo_dead_none, - => false, - }) wip_mir_log.debug("{}", .{self.fmtWipMir(result_index)}); + wip_mir_log.debug("{}", .{self.fmtWipMir(result_index)}); return result_index; } @@ -2218,7 +2220,7 @@ fn gen(self: *Self) InnerError!void { // Drop them off at the rbrace. _ = try self.addInst(.{ .tag = .pseudo, - .ops = .pseudo_dbg_line_line_column, + .ops = .pseudo_dbg_line_stmt_line_column, .data = .{ .line_column = .{ .line = self.end_di_line, .column = self.end_di_column, @@ -2426,6 +2428,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .try_ptr_cold => try self.airTryPtr(inst), // TODO .dbg_stmt => try self.airDbgStmt(inst), + .dbg_empty_stmt => try self.airDbgEmptyStmt(), .dbg_inline_block => try self.airDbgInlineBlock(inst), .dbg_var_ptr, .dbg_var_val, @@ -13281,7 +13284,7 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { const dbg_stmt = self.air.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt; _ = try self.addInst(.{ .tag = .pseudo, - .ops = .pseudo_dbg_line_line_column, + .ops = .pseudo_dbg_line_stmt_line_column, .data = .{ .line_column = .{ .line = dbg_stmt.line, .column = dbg_stmt.column, @@ -13290,6 +13293,14 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { self.finishAirBookkeeping(); } +fn airDbgEmptyStmt(self: *Self) !void { + if (self.mir_instructions.len > 0 and + self.mir_instructions.items(.ops)[self.mir_instructions.len - 1] == .pseudo_dbg_line_stmt_line_column) + self.mir_instructions.items(.ops)[self.mir_instructions.len - 1] = .pseudo_dbg_line_line_column; + try self.asmOpOnly(.{ ._, .nop }); + self.finishAirBookkeeping(); +} + fn airDbgInlineBlock(self: *Self, inst: Air.Inst.Index) !void { const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = self.air.extraData(Air.DbgInlineBlock, ty_pl.payload); diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig index 0395b7a43b..f744eb3fc4 100644 --- a/src/arch/x86_64/Emit.zig +++ b/src/arch/x86_64/Emit.zig @@ -6,8 +6,7 @@ atom_index: u32, debug_output: link.File.DebugInfoOutput, code: *std.ArrayList(u8), -prev_di_line: u32, -prev_di_column: u32, +prev_di_loc: Loc, /// Relative to the beginning of `code`. prev_di_pc: usize, @@ -263,77 +262,71 @@ pub fn emitMir(emit: *Emit) Error!void { else => unreachable, .pseudo => switch (mir_inst.ops) { else => unreachable, - .pseudo_dbg_prologue_end_none => { - switch (emit.debug_output) { - .dwarf => |dw| try dw.setPrologueEnd(), - .plan9 => {}, - .none => {}, - } + .pseudo_dbg_prologue_end_none => switch (emit.debug_output) { + .dwarf => |dwarf| try dwarf.setPrologueEnd(), + .plan9 => {}, + .none => {}, }, - .pseudo_dbg_line_line_column => try emit.dbgAdvancePCAndLine( - mir_inst.data.line_column.line, - mir_inst.data.line_column.column, - ), - .pseudo_dbg_epilogue_begin_none => { - switch (emit.debug_output) { - .dwarf => |dw| { - try dw.setEpilogueBegin(); - log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{ - emit.prev_di_line, emit.prev_di_column, - }); - try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column); - }, - .plan9 => {}, - .none => {}, - } + .pseudo_dbg_line_stmt_line_column => try emit.dbgAdvancePCAndLine(.{ + .line = mir_inst.data.line_column.line, + .column = mir_inst.data.line_column.column, + .is_stmt = true, + }), + .pseudo_dbg_line_line_column => try emit.dbgAdvancePCAndLine(.{ + .line = mir_inst.data.line_column.line, + .column = mir_inst.data.line_column.column, + .is_stmt = false, + }), + .pseudo_dbg_epilogue_begin_none => switch (emit.debug_output) { + .dwarf => |dwarf| { + try dwarf.setEpilogueBegin(); + log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{ + emit.prev_di_loc.line, emit.prev_di_loc.column, + }); + try emit.dbgAdvancePCAndLine(emit.prev_di_loc); + }, + .plan9 => {}, + .none => {}, }, - .pseudo_dbg_enter_block_none => { - switch (emit.debug_output) { - .dwarf => |dw| { - log.debug("mirDbgEnterBlock (line={d}, col={d})", .{ - emit.prev_di_line, emit.prev_di_column, - }); - try dw.enterBlock(emit.code.items.len); - }, - .plan9 => {}, - .none => {}, - } + .pseudo_dbg_enter_block_none => switch (emit.debug_output) { + .dwarf => |dwarf| { + log.debug("mirDbgEnterBlock (line={d}, col={d})", .{ + emit.prev_di_loc.line, emit.prev_di_loc.column, + }); + try dwarf.enterBlock(emit.code.items.len); + }, + .plan9 => {}, + .none => {}, }, - .pseudo_dbg_leave_block_none => { - switch (emit.debug_output) { - .dwarf => |dw| { - log.debug("mirDbgLeaveBlock (line={d}, col={d})", .{ - emit.prev_di_line, emit.prev_di_column, - }); - try dw.leaveBlock(emit.code.items.len); - }, - .plan9 => {}, - .none => {}, - } + .pseudo_dbg_leave_block_none => switch (emit.debug_output) { + .dwarf => |dwarf| { + log.debug("mirDbgLeaveBlock (line={d}, col={d})", .{ + emit.prev_di_loc.line, emit.prev_di_loc.column, + }); + try dwarf.leaveBlock(emit.code.items.len); + }, + .plan9 => {}, + .none => {}, }, - .pseudo_dbg_enter_inline_func => { - switch (emit.debug_output) { - .dwarf => |dw| { - log.debug("mirDbgEnterInline (line={d}, col={d})", .{ - emit.prev_di_line, emit.prev_di_column, - }); - try dw.enterInlineFunc(mir_inst.data.func, emit.code.items.len, emit.prev_di_line, emit.prev_di_column); - }, - .plan9 => {}, - .none => {}, - } + .pseudo_dbg_enter_inline_func => switch (emit.debug_output) { + .dwarf => |dwarf| { + log.debug("mirDbgEnterInline (line={d}, col={d})", .{ + emit.prev_di_loc.line, emit.prev_di_loc.column, + }); + try dwarf.enterInlineFunc(mir_inst.data.func, emit.code.items.len, emit.prev_di_loc.line, emit.prev_di_loc.column); + }, + .plan9 => {}, + .none => {}, }, - .pseudo_dbg_leave_inline_func => { - switch (emit.debug_output) { - .dwarf => |dw| { - log.debug("mirDbgLeaveInline (line={d}, col={d})", .{ - emit.prev_di_line, emit.prev_di_column, - }); - try dw.leaveInlineFunc(mir_inst.data.func, emit.code.items.len); - }, - .plan9 => {}, - .none => {}, - } + .pseudo_dbg_leave_inline_func => switch (emit.debug_output) { + .dwarf => |dwarf| { + log.debug("mirDbgLeaveInline (line={d}, col={d})", .{ + emit.prev_di_loc.line, emit.prev_di_loc.column, + }); + try dwarf.leaveInlineFunc(mir_inst.data.func, emit.code.items.len); + }, + .plan9 => {}, + .none => {}, }, .pseudo_dbg_local_a, .pseudo_dbg_local_ai_s, @@ -344,129 +337,125 @@ pub fn emitMir(emit: *Emit) Error!void { .pseudo_dbg_local_aro, .pseudo_dbg_local_af, .pseudo_dbg_local_am, - => { - switch (emit.debug_output) { - .dwarf => |dw| { - var loc_buf: [2]link.File.Dwarf.Loc = undefined; - const air_inst_index, const loc: link.File.Dwarf.Loc = switch (mir_inst.ops) { + => switch (emit.debug_output) { + .dwarf => |dwarf| { + var loc_buf: [2]link.File.Dwarf.Loc = undefined; + const air_inst_index, const loc: link.File.Dwarf.Loc = switch (mir_inst.ops) { + else => unreachable, + .pseudo_dbg_local_a => .{ mir_inst.data.a.air_inst, .empty }, + .pseudo_dbg_local_ai_s, + .pseudo_dbg_local_ai_u, + .pseudo_dbg_local_ai_64, + => .{ mir_inst.data.ai.air_inst, .{ .stack_value = stack_value: { + loc_buf[0] = switch (emit.lower.imm(mir_inst.ops, mir_inst.data.ai.i)) { + .signed => |s| .{ .consts = s }, + .unsigned => |u| .{ .constu = u }, + }; + break :stack_value &loc_buf[0]; + } } }, + .pseudo_dbg_local_as => .{ mir_inst.data.as.air_inst, .{ .addr = .{ + .sym = mir_inst.data.as.sym_index, + } } }, + .pseudo_dbg_local_aso => loc: { + const sym_off = emit.lower.mir.extraData( + bits.SymbolOffset, + mir_inst.data.ax.payload, + ).data; + break :loc .{ mir_inst.data.ax.air_inst, .{ .plus = .{ + sym: { + loc_buf[0] = .{ .addr = .{ .sym = sym_off.sym_index } }; + break :sym &loc_buf[0]; + }, + off: { + loc_buf[1] = .{ .consts = sym_off.off }; + break :off &loc_buf[1]; + }, + } } }; + }, + .pseudo_dbg_local_aro => loc: { + const air_off = emit.lower.mir.extraData( + Mir.AirOffset, + mir_inst.data.rx.payload, + ).data; + break :loc .{ air_off.air_inst, .{ .plus = .{ + reg: { + loc_buf[0] = .{ .breg = mir_inst.data.rx.r1.dwarfNum() }; + break :reg &loc_buf[0]; + }, + off: { + loc_buf[1] = .{ .consts = air_off.off }; + break :off &loc_buf[1]; + }, + } } }; + }, + .pseudo_dbg_local_af => loc: { + const reg_off = emit.lower.mir.resolveFrameAddr(emit.lower.mir.extraData( + bits.FrameAddr, + mir_inst.data.ax.payload, + ).data); + break :loc .{ mir_inst.data.ax.air_inst, .{ .plus = .{ + reg: { + loc_buf[0] = .{ .breg = reg_off.reg.dwarfNum() }; + break :reg &loc_buf[0]; + }, + off: { + loc_buf[1] = .{ .consts = reg_off.off }; + break :off &loc_buf[1]; + }, + } } }; + }, + .pseudo_dbg_local_am => loc: { + const mem = emit.lower.mem(mir_inst.data.ax.payload); + break :loc .{ mir_inst.data.ax.air_inst, .{ .plus = .{ + base: { + loc_buf[0] = switch (mem.base()) { + .none => .{ .constu = 0 }, + .reg => |reg| .{ .breg = reg.dwarfNum() }, + .frame => unreachable, + .reloc => |sym_index| .{ .addr = .{ .sym = sym_index } }, + }; + break :base &loc_buf[0]; + }, + disp: { + loc_buf[1] = switch (mem.disp()) { + .signed => |s| .{ .consts = s }, + .unsigned => |u| .{ .constu = u }, + }; + break :disp &loc_buf[1]; + }, + } } }; + }, + }; + const ip = &emit.lower.bin_file.comp.zcu.?.intern_pool; + const air_inst = emit.air.instructions.get(@intFromEnum(air_inst_index)); + const name: Air.NullTerminatedString = switch (air_inst.tag) { + else => unreachable, + .arg => air_inst.data.arg.name, + .dbg_var_ptr, .dbg_var_val, .dbg_arg_inline => @enumFromInt(air_inst.data.pl_op.payload), + }; + try dwarf.genLocalDebugInfo( + switch (air_inst.tag) { else => unreachable, - .pseudo_dbg_local_a => .{ mir_inst.data.a.air_inst, .empty }, - .pseudo_dbg_local_ai_s, - .pseudo_dbg_local_ai_u, - .pseudo_dbg_local_ai_64, - => .{ mir_inst.data.ai.air_inst, .{ .stack_value = stack_value: { - loc_buf[0] = switch (emit.lower.imm(mir_inst.ops, mir_inst.data.ai.i)) { - .signed => |s| .{ .consts = s }, - .unsigned => |u| .{ .constu = u }, - }; - break :stack_value &loc_buf[0]; - } } }, - .pseudo_dbg_local_as => .{ mir_inst.data.as.air_inst, .{ .addr = .{ - .sym = mir_inst.data.as.sym_index, - } } }, - .pseudo_dbg_local_aso => loc: { - const sym_off = emit.lower.mir.extraData( - bits.SymbolOffset, - mir_inst.data.ax.payload, - ).data; - break :loc .{ mir_inst.data.ax.air_inst, .{ .plus = .{ - sym: { - loc_buf[0] = .{ .addr = .{ .sym = sym_off.sym_index } }; - break :sym &loc_buf[0]; - }, - off: { - loc_buf[1] = .{ .consts = sym_off.off }; - break :off &loc_buf[1]; - }, - } } }; - }, - .pseudo_dbg_local_aro => loc: { - const air_off = emit.lower.mir.extraData( - Mir.AirOffset, - mir_inst.data.rx.payload, - ).data; - break :loc .{ air_off.air_inst, .{ .plus = .{ - reg: { - loc_buf[0] = .{ .breg = mir_inst.data.rx.r1.dwarfNum() }; - break :reg &loc_buf[0]; - }, - off: { - loc_buf[1] = .{ .consts = air_off.off }; - break :off &loc_buf[1]; - }, - } } }; - }, - .pseudo_dbg_local_af => loc: { - const reg_off = emit.lower.mir.resolveFrameAddr(emit.lower.mir.extraData( - bits.FrameAddr, - mir_inst.data.ax.payload, - ).data); - break :loc .{ mir_inst.data.ax.air_inst, .{ .plus = .{ - reg: { - loc_buf[0] = .{ .breg = reg_off.reg.dwarfNum() }; - break :reg &loc_buf[0]; - }, - off: { - loc_buf[1] = .{ .consts = reg_off.off }; - break :off &loc_buf[1]; - }, - } } }; - }, - .pseudo_dbg_local_am => loc: { - const mem = emit.lower.mem(mir_inst.data.ax.payload); - break :loc .{ mir_inst.data.ax.air_inst, .{ .plus = .{ - base: { - loc_buf[0] = switch (mem.base()) { - .none => .{ .constu = 0 }, - .reg => |reg| .{ .breg = reg.dwarfNum() }, - .frame => unreachable, - .reloc => |sym_index| .{ .addr = .{ .sym = sym_index } }, - }; - break :base &loc_buf[0]; - }, - disp: { - loc_buf[1] = switch (mem.disp()) { - .signed => |s| .{ .consts = s }, - .unsigned => |u| .{ .constu = u }, - }; - break :disp &loc_buf[1]; - }, - } } }; - }, - }; - const ip = &emit.lower.bin_file.comp.zcu.?.intern_pool; - const air_inst = emit.air.instructions.get(@intFromEnum(air_inst_index)); - const name: Air.NullTerminatedString = switch (air_inst.tag) { + .arg, .dbg_arg_inline => .local_arg, + .dbg_var_ptr, .dbg_var_val => .local_var, + }, + name.toSlice(emit.air), + switch (air_inst.tag) { else => unreachable, - .arg => air_inst.data.arg.name, - .dbg_var_ptr, .dbg_var_val, .dbg_arg_inline => @enumFromInt(air_inst.data.pl_op.payload), - }; - try dw.genLocalDebugInfo( - switch (air_inst.tag) { - else => unreachable, - .arg, .dbg_arg_inline => .local_arg, - .dbg_var_ptr, .dbg_var_val => .local_var, - }, - name.toSlice(emit.air), - switch (air_inst.tag) { - else => unreachable, - .arg => emit.air.typeOfIndex(air_inst_index, ip), - .dbg_var_ptr => emit.air.typeOf(air_inst.data.pl_op.operand, ip).childTypeIp(ip), - .dbg_var_val, .dbg_arg_inline => emit.air.typeOf(air_inst.data.pl_op.operand, ip), - }, - loc, - ); - }, - .plan9 => {}, - .none => {}, - } + .arg => emit.air.typeOfIndex(air_inst_index, ip), + .dbg_var_ptr => emit.air.typeOf(air_inst.data.pl_op.operand, ip).childTypeIp(ip), + .dbg_var_val, .dbg_arg_inline => emit.air.typeOf(air_inst.data.pl_op.operand, ip), + }, + loc, + ); + }, + .plan9 => {}, + .none => {}, }, - .pseudo_dbg_var_args_none => { - switch (emit.debug_output) { - .dwarf => |dw| try dw.genVarArgsDebugInfo(), - .plan9 => {}, - .none => {}, - } + .pseudo_dbg_var_args_none => switch (emit.debug_output) { + .dwarf => |dwarf| try dwarf.genVarArgsDebugInfo(), + .plan9 => {}, + .none => {}, }, .pseudo_dead_none => {}, }, @@ -515,16 +504,22 @@ fn fixupRelocs(emit: *Emit) Error!void { } } -fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void { - const delta_line = @as(i33, line) - @as(i33, emit.prev_di_line); +const Loc = struct { + line: u32, + column: u32, + is_stmt: bool, +}; + +fn dbgAdvancePCAndLine(emit: *Emit, loc: Loc) Error!void { + const delta_line = @as(i33, loc.line) - @as(i33, emit.prev_di_loc.line); const delta_pc: usize = emit.code.items.len - emit.prev_di_pc; log.debug(" (advance pc={d} and line={d})", .{ delta_pc, delta_line }); switch (emit.debug_output) { - .dwarf => |dw| { - if (column != emit.prev_di_column) try dw.setColumn(column); - try dw.advancePCAndLine(delta_line, delta_pc); - emit.prev_di_line = line; - emit.prev_di_column = column; + .dwarf => |dwarf| { + if (loc.is_stmt != emit.prev_di_loc.is_stmt) try dwarf.negateStmt(); + if (loc.column != emit.prev_di_loc.column) try dwarf.setColumn(loc.column); + try dwarf.advancePCAndLine(delta_line, delta_pc); + emit.prev_di_loc = loc; emit.prev_di_pc = emit.code.items.len; }, .plan9 => |dbg_out| { @@ -553,11 +548,10 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void { // we don't need to do anything, because adding the pc quanta does it for us } else unreachable; if (dbg_out.start_line == null) - dbg_out.start_line = emit.prev_di_line; - dbg_out.end_line = line; + dbg_out.start_line = emit.prev_di_loc.line; + dbg_out.end_line = loc.line; // only do this if the pc changed - emit.prev_di_line = line; - emit.prev_di_column = column; + emit.prev_di_loc = loc; emit.prev_di_pc = emit.code.items.len; }, .none => {}, diff --git a/src/arch/x86_64/Lower.zig b/src/arch/x86_64/Lower.zig index 6ac79378c1..015b3ba12e 100644 --- a/src/arch/x86_64/Lower.zig +++ b/src/arch/x86_64/Lower.zig @@ -310,6 +310,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { }), .pseudo_dbg_prologue_end_none, + .pseudo_dbg_line_stmt_line_column, .pseudo_dbg_line_line_column, .pseudo_dbg_epilogue_begin_none, .pseudo_dbg_enter_block_none, diff --git a/src/arch/x86_64/Mir.zig b/src/arch/x86_64/Mir.zig index 0e9d010758..a7f308b7b4 100644 --- a/src/arch/x86_64/Mir.zig +++ b/src/arch/x86_64/Mir.zig @@ -930,7 +930,10 @@ pub const Inst = struct { /// End of prologue pseudo_dbg_prologue_end_none, - /// Update debug line + /// Update debug line with is_stmt register set + /// Uses `line_column` payload. + pseudo_dbg_line_stmt_line_column, + /// Update debug line with is_stmt register clear /// Uses `line_column` payload. pseudo_dbg_line_line_column, /// Start of epilogue diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 0410023588..56466b4395 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -3289,6 +3289,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, .try_ptr_cold => try airTryPtr(f, inst), .dbg_stmt => try airDbgStmt(f, inst), + .dbg_empty_stmt => try airDbgEmptyStmt(f, inst), .dbg_var_ptr, .dbg_var_val, .dbg_arg_inline => try airDbgVar(f, inst), .float_from_int, @@ -4601,6 +4602,11 @@ fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue { return .none; } +fn airDbgEmptyStmt(f: *Function, _: Air.Inst.Index) !CValue { + try f.object.writer().writeAll("(void)0;\n"); + return .none; +} + fn airDbgInlineBlock(f: *Function, inst: Air.Inst.Index) !CValue { const pt = f.object.dg.pt; const zcu = pt.zcu; diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index fb20d4d622..d0b12350c0 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -5391,6 +5391,7 @@ pub const FuncGen = struct { .inferred_alloc, .inferred_alloc_comptime => unreachable, .dbg_stmt => try self.airDbgStmt(inst), + .dbg_empty_stmt => try self.airDbgEmptyStmt(inst), .dbg_var_ptr => try self.airDbgVarPtr(inst), .dbg_var_val => try self.airDbgVarVal(inst, false), .dbg_arg_inline => try self.airDbgVarVal(inst, true), @@ -7433,6 +7434,12 @@ pub const FuncGen = struct { return .none; } + fn airDbgEmptyStmt(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { + _ = self; + _ = inst; + return .none; + } + fn airDbgInlineBlock(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = self.air.extraData(Air.DbgInlineBlock, ty_pl.payload); diff --git a/src/dev.zig b/src/dev.zig index 0d365c3e19..d623a708e7 100644 --- a/src/dev.zig +++ b/src/dev.zig @@ -81,6 +81,7 @@ pub const Env = enum { => true, .cc_command, .translate_c_command, + .fmt_command, .jit_command, .fetch_command, .init_command, @@ -168,6 +169,7 @@ pub const Feature = enum { clang_command, cc_command, translate_c_command, + fmt_command, jit_command, fetch_command, init_command, diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index 6653a8309a..afdc5d1d48 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -1474,6 +1474,11 @@ pub const WipNav = struct { try uleb128(dlw, column + 1); } + pub fn negateStmt(wip_nav: *WipNav) error{OutOfMemory}!void { + const dlw = wip_nav.debug_line.writer(wip_nav.dwarf.gpa); + try dlw.writeByte(DW.LNS.negate_stmt); + } + pub fn setPrologueEnd(wip_nav: *WipNav) error{OutOfMemory}!void { const dlw = wip_nav.debug_line.writer(wip_nav.dwarf.gpa); try dlw.writeByte(DW.LNS.set_prologue_end); diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 1e29ab8bf6..effe12539c 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -1496,7 +1496,7 @@ pub fn updateFunc( }); defer gpa.free(name); const osec = if (self.text_index) |sect_sym_index| - self.symbol(sect_sym_index).output_section_index + self.symbol(sect_sym_index).outputShndx(elf_file).? else osec: { const osec = try elf_file.addSection(.{ .name = try elf_file.insertShString(".text"), diff --git a/src/main.zig b/src/main.zig index 291820cb75..13e24d8c25 100644 --- a/src/main.zig +++ b/src/main.zig @@ -309,6 +309,7 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { .server = use_server, }); } else if (mem.eql(u8, cmd, "fmt")) { + dev.check(.fmt_command); return @import("fmt.zig").run(gpa, arena, cmd_args); } else if (mem.eql(u8, cmd, "objcopy")) { return jitCmd(gpa, arena, cmd_args, .{ diff --git a/src/print_air.zig b/src/print_air.zig index 6a3f31a27c..280d05edfa 100644 --- a/src/print_air.zig +++ b/src/print_air.zig @@ -202,6 +202,7 @@ const Writer = struct { .trap, .breakpoint, + .dbg_empty_stmt, .unreach, .ret_addr, .frame_addr, diff --git a/src/print_zir.zig b/src/print_zir.zig index b8f4432e72..808ead0e79 100644 --- a/src/print_zir.zig +++ b/src/print_zir.zig @@ -621,6 +621,8 @@ const Writer = struct { .field_parent_ptr => try self.writeFieldParentPtr(stream, extended), .builtin_value => try self.writeBuiltinValue(stream, extended), .inplace_arith_result_ty => try self.writeInplaceArithResultTy(stream, extended), + + .dbg_empty_stmt => try stream.writeAll("))"), } } diff --git a/test/src/Debugger.zig b/test/src/Debugger.zig index b4b453700d..1e2289eb11 100644 --- a/test/src/Debugger.zig +++ b/test/src/Debugger.zig @@ -808,6 +808,424 @@ pub fn addTestsForTarget(db: *Debugger, target: Target) void { \\1 breakpoints deleted; 0 breakpoint locations disabled. }, ); + db.addLldbTest( + "step_single_stmt_loops", + target, + &.{ + .{ + .path = "step_single_stmt_loops.zig", + .source = + \\pub fn main() void { + \\ var x: u32 = 0; + \\ for (0..3) |_| { + \\ x +%= 1; + \\ } + \\ { + \\ var i: u32 = 0; + \\ while (i < 3) : (i +%= 1) { + \\ x +%= 1; + \\ } + \\ } + \\ { + \\ var i: u32 = 0; + \\ while (i < 3) { + \\ i +%= 1; + \\ } + \\ } + \\ inline for (0..3) |_| { + \\ x +%= 1; + \\ } + \\ { + \\ comptime var i: u32 = 0; + \\ inline while (i < 3) : (i +%= 1) { + \\ x +%= 1; + \\ } + \\ } + \\ { + \\ comptime var i: u32 = 0; + \\ inline while (i < 3) { + \\ i +%= 1; + \\ } + \\ } + \\ x +%= 1; + \\} + \\ + , + }, + }, + \\breakpoint set --name step_single_stmt_loops.main + \\process launch + \\thread step-in + \\#00 + \\frame variable x + \\thread step-in + \\#01 + \\frame variable x + \\thread step-in + \\#02 + \\frame variable x + \\thread step-in + \\#03 + \\frame variable x + \\thread step-in + \\#04 + \\frame variable x + \\thread step-in + \\#05 + \\frame variable x + \\thread step-in + \\#06 + \\frame variable x + \\thread step-in + \\#07 + \\frame variable x + \\thread step-in + \\#08 + \\frame variable x + \\thread step-in + \\#09 + \\frame variable x + \\thread step-in + \\#10 + \\frame variable x + \\thread step-in + \\#11 + \\frame variable x + \\thread step-in + \\#12 + \\frame variable x + \\thread step-in + \\#13 + \\frame variable x + \\thread step-in + \\#14 + \\frame variable x + \\thread step-in + \\#15 + \\frame variable x + \\thread step-in + \\#16 + \\frame variable x + \\thread step-in + \\#17 + \\frame variable x + \\thread step-in + \\#18 + \\frame variable x + \\thread step-in + \\#19 + \\frame variable x + \\thread step-in + \\#20 + \\frame variable x + \\thread step-in + \\#21 + \\frame variable x + \\thread step-in + \\#22 + \\frame variable x + \\thread step-in + \\#23 + \\frame variable x + \\thread step-in + \\#24 + \\frame variable x + \\thread step-in + \\#25 + \\frame variable x + \\thread step-in + \\#26 + \\frame variable x + \\thread step-in + \\#27 + \\frame variable x + \\thread step-in + \\#28 + \\frame variable x + \\thread step-in + \\#29 + \\frame variable x + \\thread step-in + \\#30 + \\frame variable x + \\thread step-in + \\#31 + \\frame variable x + \\thread step-in + \\#32 + \\frame variable x + \\thread step-in + \\#33 + \\frame variable x + \\thread step-in + \\#34 + \\frame variable x + \\thread step-in + \\#35 + \\frame variable x + \\thread step-in + \\#36 + \\frame variable x + \\thread step-in + \\#37 + \\frame variable x + \\thread step-in + \\#38 + \\frame variable x + \\thread step-in + \\#39 + \\frame variable x + \\thread step-in + \\#40 + \\frame variable x + \\thread step-in + \\#41 + \\frame variable x + \\thread step-in + \\#42 + \\frame variable x + \\thread step-in + \\#43 + \\frame variable x + \\thread step-in + \\#44 + \\frame variable x + \\thread step-in + \\#45 + \\frame variable x + \\ + , + &.{ + \\(lldb) #00 + \\(lldb) frame variable x + \\(u32) x = 0 + \\(lldb) thread step-in + , + \\(lldb) #01 + \\(lldb) frame variable x + \\(u32) x = 0 + \\(lldb) thread step-in + , + \\(lldb) #02 + \\(lldb) frame variable x + \\(u32) x = 1 + \\(lldb) thread step-in + , + \\(lldb) #03 + \\(lldb) frame variable x + \\(u32) x = 1 + \\(lldb) thread step-in + , + \\(lldb) #04 + \\(lldb) frame variable x + \\(u32) x = 1 + \\(lldb) thread step-in + , + \\(lldb) #05 + \\(lldb) frame variable x + \\(u32) x = 2 + \\(lldb) thread step-in + , + \\(lldb) #06 + \\(lldb) frame variable x + \\(u32) x = 2 + \\(lldb) thread step-in + , + \\(lldb) #07 + \\(lldb) frame variable x + \\(u32) x = 2 + \\(lldb) thread step-in + , + \\(lldb) #08 + \\(lldb) frame variable x + \\(u32) x = 3 + \\(lldb) thread step-in + , + \\(lldb) #09 + \\(lldb) frame variable x + \\(u32) x = 3 + \\(lldb) thread step-in + , + \\(lldb) #10 + \\(lldb) frame variable x + \\(u32) x = 3 + \\(lldb) thread step-in + , + \\(lldb) #11 + \\(lldb) frame variable x + \\(u32) x = 3 + \\(lldb) thread step-in + , + \\(lldb) #12 + \\(lldb) frame variable x + \\(u32) x = 3 + \\(lldb) thread step-in + , + \\(lldb) #13 + \\(lldb) frame variable x + \\(u32) x = 4 + \\(lldb) thread step-in + , + \\(lldb) #14 + \\(lldb) frame variable x + \\(u32) x = 4 + \\(lldb) thread step-in + , + \\(lldb) #15 + \\(lldb) frame variable x + \\(u32) x = 4 + \\(lldb) thread step-in + , + \\(lldb) #16 + \\(lldb) frame variable x + \\(u32) x = 5 + \\(lldb) thread step-in + , + \\(lldb) #17 + \\(lldb) frame variable x + \\(u32) x = 5 + \\(lldb) thread step-in + , + \\(lldb) #18 + \\(lldb) frame variable x + \\(u32) x = 5 + \\(lldb) thread step-in + , + \\(lldb) #19 + \\(lldb) frame variable x + \\(u32) x = 6 + \\(lldb) thread step-in + , + \\(lldb) #20 + \\(lldb) frame variable x + \\(u32) x = 6 + \\(lldb) thread step-in + , + \\(lldb) #21 + \\(lldb) frame variable x + \\(u32) x = 6 + \\(lldb) thread step-in + , + \\(lldb) #22 + \\(lldb) frame variable x + \\(u32) x = 6 + \\(lldb) thread step-in + , + \\(lldb) #23 + \\(lldb) frame variable x + \\(u32) x = 6 + \\(lldb) thread step-in + , + \\(lldb) #24 + \\(lldb) frame variable x + \\(u32) x = 6 + \\(lldb) thread step-in + , + \\(lldb) #25 + \\(lldb) frame variable x + \\(u32) x = 6 + \\(lldb) thread step-in + , + \\(lldb) #26 + \\(lldb) frame variable x + \\(u32) x = 6 + \\(lldb) thread step-in + , + \\(lldb) #27 + \\(lldb) frame variable x + \\(u32) x = 6 + \\(lldb) thread step-in + , + \\(lldb) #28 + \\(lldb) frame variable x + \\(u32) x = 6 + \\(lldb) thread step-in + , + \\(lldb) #29 + \\(lldb) frame variable x + \\(u32) x = 6 + \\(lldb) thread step-in + , + \\(lldb) #30 + \\(lldb) frame variable x + \\(u32) x = 6 + \\(lldb) thread step-in + , + \\(lldb) #31 + \\(lldb) frame variable x + \\(u32) x = 6 + \\(lldb) thread step-in + , + \\(lldb) #32 + \\(lldb) frame variable x + \\(u32) x = 6 + \\(lldb) thread step-in + , + \\(lldb) #33 + \\(lldb) frame variable x + \\(u32) x = 7 + \\(lldb) thread step-in + , + \\(lldb) #34 + \\(lldb) frame variable x + \\(u32) x = 7 + \\(lldb) thread step-in + , + \\(lldb) #35 + \\(lldb) frame variable x + \\(u32) x = 8 + \\(lldb) thread step-in + , + \\(lldb) #36 + \\(lldb) frame variable x + \\(u32) x = 8 + \\(lldb) thread step-in + , + \\(lldb) #37 + \\(lldb) frame variable x + \\(u32) x = 9 + \\(lldb) thread step-in + , + \\(lldb) #38 + \\(lldb) frame variable x + \\(u32) x = 9 + \\(lldb) thread step-in + , + \\(lldb) #39 + \\(lldb) frame variable x + \\(u32) x = 10 + \\(lldb) thread step-in + , + \\(lldb) #40 + \\(lldb) frame variable x + \\(u32) x = 10 + \\(lldb) thread step-in + , + \\(lldb) #41 + \\(lldb) frame variable x + \\(u32) x = 11 + \\(lldb) thread step-in + , + \\(lldb) #42 + \\(lldb) frame variable x + \\(u32) x = 11 + \\(lldb) thread step-in + , + \\(lldb) #43 + \\(lldb) frame variable x + \\(u32) x = 12 + \\(lldb) thread step-in + , + \\(lldb) #44 + \\(lldb) frame variable x + \\(u32) x = 12 + \\(lldb) thread step-in + , + \\(lldb) #45 + \\(lldb) frame variable x + \\(u32) x = 12 + }, + ); db.addLldbTest( "inline_call", target,