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.
This commit is contained in:
Jacob Young 2024-11-24 04:11:52 -05:00 committed by Andrew Kelley
parent 6d781e0955
commit c894ac09a3
25 changed files with 721 additions and 221 deletions

View File

@ -6024,7 +6024,7 @@ fn tryExpr(
if (!parent_gz.is_comptime) { if (!parent_gz.is_comptime) {
try emitDbgNode(parent_gz, node); 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) { const operand_rl: ResultInfo.Loc, const block_tag: Zir.Inst.Tag = switch (ri.rl) {
.ref => .{ .ref, .try_ptr }, .ref => .{ .ref, .try_ptr },
@ -6577,6 +6577,7 @@ fn whileExpr(
const astgen = parent_gz.astgen; const astgen = parent_gz.astgen;
const tree = astgen.tree; const tree = astgen.tree;
const token_tags = tree.tokens.items(.tag); const token_tags = tree.tokens.items(.tag);
const token_starts = tree.tokens.items(.start);
const need_rl = astgen.nodes_need_rl.contains(node); const need_rl = astgen.nodes_need_rl.contains(node);
const block_ri: ResultInfo = if (need_rl) ri else .{ 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); try checkUsed(parent_gz, &then_scope.base, then_sub_scope);
const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break"; const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break";
if (!continue_scope.endsWithNoReturn()) { 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.addBreak(break_tag, continue_block, .void_value);
} }
try continue_scope.setBlockBody(continue_block); try continue_scope.setBlockBody(continue_block);
@ -6882,6 +6893,7 @@ fn forExpr(
} }
const tree = astgen.tree; const tree = astgen.tree;
const token_tags = tree.tokens.items(.tag); const token_tags = tree.tokens.items(.tag);
const token_starts = tree.tokens.items(.start);
const node_tags = tree.nodes.items(.tag); const node_tags = tree.nodes.items(.tag);
const node_data = tree.nodes.items(.data); const node_data = tree.nodes.items(.data);
const gpa = astgen.gpa; const gpa = astgen.gpa;
@ -7087,8 +7099,18 @@ fn forExpr(
try checkUsed(parent_gz, &then_scope.base, then_sub_scope); 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); _ = try then_scope.addBreak(break_tag, cond_block, .void_value);
var else_scope = parent_gz.makeSubBlock(&cond_scope.base); var else_scope = parent_gz.makeSubBlock(&cond_scope.base);
@ -7135,6 +7157,7 @@ fn forExpr(
.lhs = index_ptr, .lhs = index_ptr,
.rhs = index_plus_one, .rhs = index_plus_one,
}); });
const repeat_tag: Zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat; const repeat_tag: Zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat;
_ = try loop_scope.addNode(repeat_tag, node); _ = try loop_scope.addNode(repeat_tag, node);
@ -7279,7 +7302,7 @@ fn switchExprErrUnion(
}; };
astgen.advanceSourceCursorToNode(operand_node); 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 raw_operand = try reachableExpr(parent_gz, scope, operand_ri, operand_node, switch_node);
const item_ri: ResultInfo = .{ .rl = .none }; 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 }; const operand_ri: ResultInfo = .{ .rl = if (any_payload_is_ref) .ref else .none };
astgen.advanceSourceCursorToNode(operand_node); 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 raw_operand = try expr(parent_gz, scope, operand_ri, operand_node);
const item_ri: ResultInfo = .{ .rl = .none }; 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) { if (!gz.is_comptime) {
try emitDbgNode(gz, node); 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; const defer_outer = &astgen.fn_block.?.base;

View File

@ -2088,6 +2088,8 @@ pub const Inst = struct {
/// `operand` is `Zir.Inst.Ref` of the loaded LHS (*not* its type). /// `operand` is `Zir.Inst.Ref` of the loaded LHS (*not* its type).
/// `small` is an `Inst.InplaceOp`. /// `small` is an `Inst.InplaceOp`.
inplace_arith_result_ty, inplace_arith_result_ty,
/// Marks a statement that can be stepped to but produces no code.
dbg_empty_stmt,
pub const InstData = struct { pub const InstData = struct {
opcode: Extended, opcode: Extended,
@ -4062,6 +4064,7 @@ fn findDeclsInner(
.branch_hint, .branch_hint,
.inplace_arith_result_ty, .inplace_arith_result_ty,
.tuple_decl, .tuple_decl,
.dbg_empty_stmt,
=> return, => return,
// `@TypeOf` has a body. // `@TypeOf` has a body.

View File

@ -460,6 +460,8 @@ pub const Inst = struct {
/// Result type is always void. /// Result type is always void.
/// Uses the `dbg_stmt` field. /// Uses the `dbg_stmt` field.
dbg_stmt, 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. /// A block that represents an inlined function call.
/// Uses the `ty_pl` field. Payload is `DbgInlineBlock`. /// Uses the `ty_pl` field. Payload is `DbgInlineBlock`.
dbg_inline_block, dbg_inline_block,
@ -1468,6 +1470,7 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)
.breakpoint, .breakpoint,
.dbg_stmt, .dbg_stmt,
.dbg_empty_stmt,
.dbg_var_ptr, .dbg_var_ptr,
.dbg_var_val, .dbg_var_val,
.dbg_arg_inline, .dbg_arg_inline,
@ -1629,6 +1632,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {
.try_ptr, .try_ptr,
.try_ptr_cold, .try_ptr_cold,
.dbg_stmt, .dbg_stmt,
.dbg_empty_stmt,
.dbg_inline_block, .dbg_inline_block,
.dbg_var_ptr, .dbg_var_ptr,
.dbg_var_val, .dbg_var_val,

View File

@ -417,6 +417,7 @@ fn checkBody(air: Air, body: []const Air.Inst.Index, zcu: *Zcu) bool {
.work_group_size, .work_group_size,
.work_group_id, .work_group_id,
.dbg_stmt, .dbg_stmt,
.dbg_empty_stmt,
.err_return_trace, .err_return_trace,
.save_err_return_trace_index, .save_err_return_trace_index,
.repeat, .repeat,

View File

@ -334,6 +334,7 @@ pub fn categorizeOperand(
.repeat, .repeat,
.switch_dispatch, .switch_dispatch,
.dbg_stmt, .dbg_stmt,
.dbg_empty_stmt,
.unreach, .unreach,
.ret_addr, .ret_addr,
.frame_addr, .frame_addr,
@ -973,6 +974,7 @@ fn analyzeInst(
.ret_ptr, .ret_ptr,
.breakpoint, .breakpoint,
.dbg_stmt, .dbg_stmt,
.dbg_empty_stmt,
.ret_addr, .ret_addr,
.frame_addr, .frame_addr,
.wasm_memory_size, .wasm_memory_size,

View File

@ -56,6 +56,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
.ret_ptr, .ret_ptr,
.breakpoint, .breakpoint,
.dbg_stmt, .dbg_stmt,
.dbg_empty_stmt,
.ret_addr, .ret_addr,
.frame_addr, .frame_addr,
.wasm_memory_size, .wasm_memory_size,

View File

@ -1355,6 +1355,11 @@ fn analyzeBodyInner(
.field_parent_ptr => try sema.zirFieldParentPtr(block, extended), .field_parent_ptr => try sema.zirFieldParentPtr(block, extended),
.builtin_value => try sema.zirBuiltinValue(block, extended), .builtin_value => try sema.zirBuiltinValue(block, extended),
.inplace_arith_result_ty => try sema.zirInplaceArithResultTy(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( fn zirDbgVar(
sema: *Sema, sema: *Sema,
block: *Block, block: *Block,

View File

@ -800,6 +800,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.try_ptr_cold => try self.airTryPtr(inst), .try_ptr_cold => try self.airTryPtr(inst),
.dbg_stmt => try self.airDbgStmt(inst), .dbg_stmt => try self.airDbgStmt(inst),
.dbg_empty_stmt => self.finishAirBookkeeping(),
.dbg_inline_block => try self.airDbgInlineBlock(inst), .dbg_inline_block => try self.airDbgInlineBlock(inst),
.dbg_var_ptr, .dbg_var_ptr,
.dbg_var_val, .dbg_var_val,

View File

@ -787,6 +787,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.try_ptr_cold => try self.airTryPtr(inst), .try_ptr_cold => try self.airTryPtr(inst),
.dbg_stmt => try self.airDbgStmt(inst), .dbg_stmt => try self.airDbgStmt(inst),
.dbg_empty_stmt => self.finishAirBookkeeping(),
.dbg_inline_block => try self.airDbgInlineBlock(inst), .dbg_inline_block => try self.airDbgInlineBlock(inst),
.dbg_var_ptr, .dbg_var_ptr,
.dbg_var_val, .dbg_var_val,

View File

@ -1593,6 +1593,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
.frame_addr => try func.airFrameAddress(inst), .frame_addr => try func.airFrameAddress(inst),
.cond_br => try func.airCondBr(inst), .cond_br => try func.airCondBr(inst),
.dbg_stmt => try func.airDbgStmt(inst), .dbg_stmt => try func.airDbgStmt(inst),
.dbg_empty_stmt => func.finishAirBookkeeping(),
.fptrunc => try func.airFptrunc(inst), .fptrunc => try func.airFptrunc(inst),
.fpext => try func.airFpext(inst), .fpext => try func.airFpext(inst),
.intcast => try func.airIntCast(inst), .intcast => try func.airIntCast(inst),

View File

@ -642,6 +642,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.try_ptr_cold => @panic("TODO try self.airTryPtrCold(inst)"), .try_ptr_cold => @panic("TODO try self.airTryPtrCold(inst)"),
.dbg_stmt => try self.airDbgStmt(inst), .dbg_stmt => try self.airDbgStmt(inst),
.dbg_empty_stmt => self.finishAirBookkeeping(),
.dbg_inline_block => try self.airDbgInlineBlock(inst), .dbg_inline_block => try self.airDbgInlineBlock(inst),
.dbg_var_ptr, .dbg_var_ptr,
.dbg_var_val, .dbg_var_val,

View File

@ -1924,6 +1924,7 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
.try_ptr_cold => func.airTryPtr(inst), .try_ptr_cold => func.airTryPtr(inst),
.dbg_stmt => func.airDbgStmt(inst), .dbg_stmt => func.airDbgStmt(inst),
.dbg_empty_stmt => try func.finishAir(inst, .none, &.{}),
.dbg_inline_block => func.airDbgInlineBlock(inst), .dbg_inline_block => func.airDbgInlineBlock(inst),
.dbg_var_ptr => func.airDbgVar(inst, .local_var, true), .dbg_var_ptr => func.airDbgVar(inst, .local_var, true),
.dbg_var_val => func.airDbgVar(inst, .local_var, false), .dbg_var_val => func.airDbgVar(inst, .local_var, false),

View File

@ -961,9 +961,16 @@ pub fn generate(
}, },
.debug_output = debug_output, .debug_output = debug_output,
.code = code, .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_pc = 0,
.prev_di_line = func.lbrace_line,
.prev_di_column = func.lbrace_column,
}; };
defer emit.deinit(); defer emit.deinit();
emit.emitMir() catch |err| switch (err) { emit.emitMir() catch |err| switch (err) {
@ -1066,9 +1073,8 @@ pub fn generateLazy(
}, },
.debug_output = debug_output, .debug_output = debug_output,
.code = code, .code = code,
.prev_di_loc = undefined, // no debug info yet
.prev_di_pc = 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(); defer emit.deinit();
emit.emitMir() catch |err| switch (err) { emit.emitMir() catch |err| switch (err) {
@ -1194,13 +1200,16 @@ fn formatWipMir(
switch (mir_inst.ops) { switch (mir_inst.ops) {
else => unreachable, else => unreachable,
.pseudo_dbg_prologue_end_none, .pseudo_dbg_prologue_end_none,
.pseudo_dbg_line_line_column,
.pseudo_dbg_epilogue_begin_none, .pseudo_dbg_epilogue_begin_none,
.pseudo_dbg_enter_block_none, .pseudo_dbg_enter_block_none,
.pseudo_dbg_leave_block_none, .pseudo_dbg_leave_block_none,
.pseudo_dbg_var_args_none, .pseudo_dbg_var_args_none,
.pseudo_dead_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(" {}", .{ .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), 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); try self.mir_instructions.ensureUnusedCapacity(gpa, 1);
const result_index: Mir.Inst.Index = @intCast(self.mir_instructions.len); const result_index: Mir.Inst.Index = @intCast(self.mir_instructions.len);
self.mir_instructions.appendAssumeCapacity(inst); self.mir_instructions.appendAssumeCapacity(inst);
if (inst.tag != .pseudo or switch (inst.ops) { wip_mir_log.debug("{}", .{self.fmtWipMir(result_index)});
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)});
return result_index; return result_index;
} }
@ -2218,7 +2220,7 @@ fn gen(self: *Self) InnerError!void {
// Drop them off at the rbrace. // Drop them off at the rbrace.
_ = try self.addInst(.{ _ = try self.addInst(.{
.tag = .pseudo, .tag = .pseudo,
.ops = .pseudo_dbg_line_line_column, .ops = .pseudo_dbg_line_stmt_line_column,
.data = .{ .line_column = .{ .data = .{ .line_column = .{
.line = self.end_di_line, .line = self.end_di_line,
.column = self.end_di_column, .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 .try_ptr_cold => try self.airTryPtr(inst), // TODO
.dbg_stmt => try self.airDbgStmt(inst), .dbg_stmt => try self.airDbgStmt(inst),
.dbg_empty_stmt => try self.airDbgEmptyStmt(),
.dbg_inline_block => try self.airDbgInlineBlock(inst), .dbg_inline_block => try self.airDbgInlineBlock(inst),
.dbg_var_ptr, .dbg_var_ptr,
.dbg_var_val, .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; const dbg_stmt = self.air.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt;
_ = try self.addInst(.{ _ = try self.addInst(.{
.tag = .pseudo, .tag = .pseudo,
.ops = .pseudo_dbg_line_line_column, .ops = .pseudo_dbg_line_stmt_line_column,
.data = .{ .line_column = .{ .data = .{ .line_column = .{
.line = dbg_stmt.line, .line = dbg_stmt.line,
.column = dbg_stmt.column, .column = dbg_stmt.column,
@ -13290,6 +13293,14 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
self.finishAirBookkeeping(); 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 { fn airDbgInlineBlock(self: *Self, inst: Air.Inst.Index) !void {
const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const extra = self.air.extraData(Air.DbgInlineBlock, ty_pl.payload); const extra = self.air.extraData(Air.DbgInlineBlock, ty_pl.payload);

View File

@ -6,8 +6,7 @@ atom_index: u32,
debug_output: link.File.DebugInfoOutput, debug_output: link.File.DebugInfoOutput,
code: *std.ArrayList(u8), code: *std.ArrayList(u8),
prev_di_line: u32, prev_di_loc: Loc,
prev_di_column: u32,
/// Relative to the beginning of `code`. /// Relative to the beginning of `code`.
prev_di_pc: usize, prev_di_pc: usize,
@ -263,77 +262,71 @@ pub fn emitMir(emit: *Emit) Error!void {
else => unreachable, else => unreachable,
.pseudo => switch (mir_inst.ops) { .pseudo => switch (mir_inst.ops) {
else => unreachable, else => unreachable,
.pseudo_dbg_prologue_end_none => { .pseudo_dbg_prologue_end_none => switch (emit.debug_output) {
switch (emit.debug_output) { .dwarf => |dwarf| try dwarf.setPrologueEnd(),
.dwarf => |dw| try dw.setPrologueEnd(), .plan9 => {},
.plan9 => {}, .none => {},
.none => {},
}
}, },
.pseudo_dbg_line_line_column => try emit.dbgAdvancePCAndLine( .pseudo_dbg_line_stmt_line_column => try emit.dbgAdvancePCAndLine(.{
mir_inst.data.line_column.line, .line = mir_inst.data.line_column.line,
mir_inst.data.line_column.column, .column = mir_inst.data.line_column.column,
), .is_stmt = true,
.pseudo_dbg_epilogue_begin_none => { }),
switch (emit.debug_output) { .pseudo_dbg_line_line_column => try emit.dbgAdvancePCAndLine(.{
.dwarf => |dw| { .line = mir_inst.data.line_column.line,
try dw.setEpilogueBegin(); .column = mir_inst.data.line_column.column,
log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{ .is_stmt = false,
emit.prev_di_line, emit.prev_di_column, }),
}); .pseudo_dbg_epilogue_begin_none => switch (emit.debug_output) {
try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column); .dwarf => |dwarf| {
}, try dwarf.setEpilogueBegin();
.plan9 => {}, log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{
.none => {}, emit.prev_di_loc.line, emit.prev_di_loc.column,
} });
try emit.dbgAdvancePCAndLine(emit.prev_di_loc);
},
.plan9 => {},
.none => {},
}, },
.pseudo_dbg_enter_block_none => { .pseudo_dbg_enter_block_none => switch (emit.debug_output) {
switch (emit.debug_output) { .dwarf => |dwarf| {
.dwarf => |dw| { log.debug("mirDbgEnterBlock (line={d}, col={d})", .{
log.debug("mirDbgEnterBlock (line={d}, col={d})", .{ emit.prev_di_loc.line, emit.prev_di_loc.column,
emit.prev_di_line, emit.prev_di_column, });
}); try dwarf.enterBlock(emit.code.items.len);
try dw.enterBlock(emit.code.items.len); },
}, .plan9 => {},
.plan9 => {}, .none => {},
.none => {},
}
}, },
.pseudo_dbg_leave_block_none => { .pseudo_dbg_leave_block_none => switch (emit.debug_output) {
switch (emit.debug_output) { .dwarf => |dwarf| {
.dwarf => |dw| { log.debug("mirDbgLeaveBlock (line={d}, col={d})", .{
log.debug("mirDbgLeaveBlock (line={d}, col={d})", .{ emit.prev_di_loc.line, emit.prev_di_loc.column,
emit.prev_di_line, emit.prev_di_column, });
}); try dwarf.leaveBlock(emit.code.items.len);
try dw.leaveBlock(emit.code.items.len); },
}, .plan9 => {},
.plan9 => {}, .none => {},
.none => {},
}
}, },
.pseudo_dbg_enter_inline_func => { .pseudo_dbg_enter_inline_func => switch (emit.debug_output) {
switch (emit.debug_output) { .dwarf => |dwarf| {
.dwarf => |dw| { log.debug("mirDbgEnterInline (line={d}, col={d})", .{
log.debug("mirDbgEnterInline (line={d}, col={d})", .{ emit.prev_di_loc.line, emit.prev_di_loc.column,
emit.prev_di_line, emit.prev_di_column, });
}); try dwarf.enterInlineFunc(mir_inst.data.func, emit.code.items.len, emit.prev_di_loc.line, emit.prev_di_loc.column);
try dw.enterInlineFunc(mir_inst.data.func, emit.code.items.len, emit.prev_di_line, emit.prev_di_column); },
}, .plan9 => {},
.plan9 => {}, .none => {},
.none => {},
}
}, },
.pseudo_dbg_leave_inline_func => { .pseudo_dbg_leave_inline_func => switch (emit.debug_output) {
switch (emit.debug_output) { .dwarf => |dwarf| {
.dwarf => |dw| { log.debug("mirDbgLeaveInline (line={d}, col={d})", .{
log.debug("mirDbgLeaveInline (line={d}, col={d})", .{ emit.prev_di_loc.line, emit.prev_di_loc.column,
emit.prev_di_line, emit.prev_di_column, });
}); try dwarf.leaveInlineFunc(mir_inst.data.func, emit.code.items.len);
try dw.leaveInlineFunc(mir_inst.data.func, emit.code.items.len); },
}, .plan9 => {},
.plan9 => {}, .none => {},
.none => {},
}
}, },
.pseudo_dbg_local_a, .pseudo_dbg_local_a,
.pseudo_dbg_local_ai_s, .pseudo_dbg_local_ai_s,
@ -344,129 +337,125 @@ pub fn emitMir(emit: *Emit) Error!void {
.pseudo_dbg_local_aro, .pseudo_dbg_local_aro,
.pseudo_dbg_local_af, .pseudo_dbg_local_af,
.pseudo_dbg_local_am, .pseudo_dbg_local_am,
=> { => switch (emit.debug_output) {
switch (emit.debug_output) { .dwarf => |dwarf| {
.dwarf => |dw| { var loc_buf: [2]link.File.Dwarf.Loc = undefined;
var loc_buf: [2]link.File.Dwarf.Loc = undefined; const air_inst_index, const loc: link.File.Dwarf.Loc = switch (mir_inst.ops) {
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, else => unreachable,
.pseudo_dbg_local_a => .{ mir_inst.data.a.air_inst, .empty }, .arg, .dbg_arg_inline => .local_arg,
.pseudo_dbg_local_ai_s, .dbg_var_ptr, .dbg_var_val => .local_var,
.pseudo_dbg_local_ai_u, },
.pseudo_dbg_local_ai_64, name.toSlice(emit.air),
=> .{ mir_inst.data.ai.air_inst, .{ .stack_value = stack_value: { switch (air_inst.tag) {
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, else => unreachable,
.arg => air_inst.data.arg.name, .arg => emit.air.typeOfIndex(air_inst_index, ip),
.dbg_var_ptr, .dbg_var_val, .dbg_arg_inline => @enumFromInt(air_inst.data.pl_op.payload), .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),
try dw.genLocalDebugInfo( },
switch (air_inst.tag) { loc,
else => unreachable, );
.arg, .dbg_arg_inline => .local_arg, },
.dbg_var_ptr, .dbg_var_val => .local_var, .plan9 => {},
}, .none => {},
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 => {},
}
}, },
.pseudo_dbg_var_args_none => { .pseudo_dbg_var_args_none => switch (emit.debug_output) {
switch (emit.debug_output) { .dwarf => |dwarf| try dwarf.genVarArgsDebugInfo(),
.dwarf => |dw| try dw.genVarArgsDebugInfo(), .plan9 => {},
.plan9 => {}, .none => {},
.none => {},
}
}, },
.pseudo_dead_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 Loc = struct {
const delta_line = @as(i33, line) - @as(i33, emit.prev_di_line); 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; const delta_pc: usize = emit.code.items.len - emit.prev_di_pc;
log.debug(" (advance pc={d} and line={d})", .{ delta_pc, delta_line }); log.debug(" (advance pc={d} and line={d})", .{ delta_pc, delta_line });
switch (emit.debug_output) { switch (emit.debug_output) {
.dwarf => |dw| { .dwarf => |dwarf| {
if (column != emit.prev_di_column) try dw.setColumn(column); if (loc.is_stmt != emit.prev_di_loc.is_stmt) try dwarf.negateStmt();
try dw.advancePCAndLine(delta_line, delta_pc); if (loc.column != emit.prev_di_loc.column) try dwarf.setColumn(loc.column);
emit.prev_di_line = line; try dwarf.advancePCAndLine(delta_line, delta_pc);
emit.prev_di_column = column; emit.prev_di_loc = loc;
emit.prev_di_pc = emit.code.items.len; emit.prev_di_pc = emit.code.items.len;
}, },
.plan9 => |dbg_out| { .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 // we don't need to do anything, because adding the pc quanta does it for us
} else unreachable; } else unreachable;
if (dbg_out.start_line == null) if (dbg_out.start_line == null)
dbg_out.start_line = emit.prev_di_line; dbg_out.start_line = emit.prev_di_loc.line;
dbg_out.end_line = line; dbg_out.end_line = loc.line;
// only do this if the pc changed // only do this if the pc changed
emit.prev_di_line = line; emit.prev_di_loc = loc;
emit.prev_di_column = column;
emit.prev_di_pc = emit.code.items.len; emit.prev_di_pc = emit.code.items.len;
}, },
.none => {}, .none => {},

View File

@ -310,6 +310,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
}), }),
.pseudo_dbg_prologue_end_none, .pseudo_dbg_prologue_end_none,
.pseudo_dbg_line_stmt_line_column,
.pseudo_dbg_line_line_column, .pseudo_dbg_line_line_column,
.pseudo_dbg_epilogue_begin_none, .pseudo_dbg_epilogue_begin_none,
.pseudo_dbg_enter_block_none, .pseudo_dbg_enter_block_none,

View File

@ -930,7 +930,10 @@ pub const Inst = struct {
/// End of prologue /// End of prologue
pseudo_dbg_prologue_end_none, 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. /// Uses `line_column` payload.
pseudo_dbg_line_line_column, pseudo_dbg_line_line_column,
/// Start of epilogue /// Start of epilogue

View File

@ -3289,6 +3289,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
.try_ptr_cold => try airTryPtr(f, inst), .try_ptr_cold => try airTryPtr(f, inst),
.dbg_stmt => try airDbgStmt(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), .dbg_var_ptr, .dbg_var_val, .dbg_arg_inline => try airDbgVar(f, inst),
.float_from_int, .float_from_int,
@ -4601,6 +4602,11 @@ fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue {
return .none; 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 { fn airDbgInlineBlock(f: *Function, inst: Air.Inst.Index) !CValue {
const pt = f.object.dg.pt; const pt = f.object.dg.pt;
const zcu = pt.zcu; const zcu = pt.zcu;

View File

@ -5391,6 +5391,7 @@ pub const FuncGen = struct {
.inferred_alloc, .inferred_alloc_comptime => unreachable, .inferred_alloc, .inferred_alloc_comptime => unreachable,
.dbg_stmt => try self.airDbgStmt(inst), .dbg_stmt => try self.airDbgStmt(inst),
.dbg_empty_stmt => try self.airDbgEmptyStmt(inst),
.dbg_var_ptr => try self.airDbgVarPtr(inst), .dbg_var_ptr => try self.airDbgVarPtr(inst),
.dbg_var_val => try self.airDbgVarVal(inst, false), .dbg_var_val => try self.airDbgVarVal(inst, false),
.dbg_arg_inline => try self.airDbgVarVal(inst, true), .dbg_arg_inline => try self.airDbgVarVal(inst, true),
@ -7433,6 +7434,12 @@ pub const FuncGen = struct {
return .none; 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 { fn airDbgInlineBlock(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const extra = self.air.extraData(Air.DbgInlineBlock, ty_pl.payload); const extra = self.air.extraData(Air.DbgInlineBlock, ty_pl.payload);

View File

@ -81,6 +81,7 @@ pub const Env = enum {
=> true, => true,
.cc_command, .cc_command,
.translate_c_command, .translate_c_command,
.fmt_command,
.jit_command, .jit_command,
.fetch_command, .fetch_command,
.init_command, .init_command,
@ -168,6 +169,7 @@ pub const Feature = enum {
clang_command, clang_command,
cc_command, cc_command,
translate_c_command, translate_c_command,
fmt_command,
jit_command, jit_command,
fetch_command, fetch_command,
init_command, init_command,

View File

@ -1474,6 +1474,11 @@ pub const WipNav = struct {
try uleb128(dlw, column + 1); 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 { pub fn setPrologueEnd(wip_nav: *WipNav) error{OutOfMemory}!void {
const dlw = wip_nav.debug_line.writer(wip_nav.dwarf.gpa); const dlw = wip_nav.debug_line.writer(wip_nav.dwarf.gpa);
try dlw.writeByte(DW.LNS.set_prologue_end); try dlw.writeByte(DW.LNS.set_prologue_end);

View File

@ -1496,7 +1496,7 @@ pub fn updateFunc(
}); });
defer gpa.free(name); defer gpa.free(name);
const osec = if (self.text_index) |sect_sym_index| 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: { else osec: {
const osec = try elf_file.addSection(.{ const osec = try elf_file.addSection(.{
.name = try elf_file.insertShString(".text"), .name = try elf_file.insertShString(".text"),

View File

@ -309,6 +309,7 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
.server = use_server, .server = use_server,
}); });
} else if (mem.eql(u8, cmd, "fmt")) { } else if (mem.eql(u8, cmd, "fmt")) {
dev.check(.fmt_command);
return @import("fmt.zig").run(gpa, arena, cmd_args); return @import("fmt.zig").run(gpa, arena, cmd_args);
} else if (mem.eql(u8, cmd, "objcopy")) { } else if (mem.eql(u8, cmd, "objcopy")) {
return jitCmd(gpa, arena, cmd_args, .{ return jitCmd(gpa, arena, cmd_args, .{

View File

@ -202,6 +202,7 @@ const Writer = struct {
.trap, .trap,
.breakpoint, .breakpoint,
.dbg_empty_stmt,
.unreach, .unreach,
.ret_addr, .ret_addr,
.frame_addr, .frame_addr,

View File

@ -621,6 +621,8 @@ const Writer = struct {
.field_parent_ptr => try self.writeFieldParentPtr(stream, extended), .field_parent_ptr => try self.writeFieldParentPtr(stream, extended),
.builtin_value => try self.writeBuiltinValue(stream, extended), .builtin_value => try self.writeBuiltinValue(stream, extended),
.inplace_arith_result_ty => try self.writeInplaceArithResultTy(stream, extended), .inplace_arith_result_ty => try self.writeInplaceArithResultTy(stream, extended),
.dbg_empty_stmt => try stream.writeAll("))"),
} }
} }

View File

@ -808,6 +808,424 @@ pub fn addTestsForTarget(db: *Debugger, target: Target) void {
\\1 breakpoints deleted; 0 breakpoint locations disabled. \\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( db.addLldbTest(
"inline_call", "inline_call",
target, target,