- Overview
- Completed Work
- Known Limitations
- Priority: OPDF Scalability (Completed)
- Feature Work Items
- Prerequisite: OPDF Format Fix — DONE
- Tier 1: High Value, Lower Complexity
- Tier 2: High Value, Higher Complexity
- Tier 3: Language Completeness
- Feature 10: Variant Records
- Feature 10b: Variant Type Support
- Feature 11: Generics (Basic Containers)
- Feature 12: Exception Metadata
- Feature 14: Compile-Time Constants
- Feature 15: Step Over and Step Into — DONE
- Feature 16: Implicit Self Field Resolution
- Feature 17: Primitive SubKind Byte — DONE
- Feature 13: Optimized Code — Register-Allocated Variables
- Upstream Contribution (Independent)
- Platform Expansion
- Architecture Summary
- Quick Reference
This document tracks the implementation progress of the Object Pascal Debug Format (OPDF) project, covering both the standalone debugger toolchain and the FPC compiler integration.
Repository: /data/devel/opdebugger (standalone debugger + opdf-lib)
FPC Branch: feature/opdf-support in /data/devel/fpc-3.3.1/src
-
✓ Feature 1:
localscommand — lists all in-scope local variables with evaluated values -
✓ Feature 1:
locals globalssubcommand — also enumerates global variables -
✓ Feature 2:
inspectcommand — structured multi-line layout for records, classes, and interfaces -
✓ Feature 3:
print <arr>[N..M]— array slice display with out-of-bounds clamping -
✓ Feature 4:
set <var> = <value>— in-process variable assignment (primitives and enums) -
✓ Feature 5:
break … if count=N— hit-count conditional breakpoints withconditionandinfo breakpointscommands -
✓ Feature 6:
display/undisplay— auto-print variables on every breakpoint stop, with out-of-scope handling -
✓ Feature 15: Step over (
next/n) and step into (step/s) — source-line-aware stepping -
✓ Feature 17:
recPrimitiveSubKind byte — compiler-emitted semantic classification (Integer, Boolean, Char, WideChar, Float, Currency) replaces name-matching heuristics in debugger -
✓ Integration tests 14–21, 25–27 covering all features; 27/27 automated tests passing
-
✓ Sentinel breakpoint pattern applied to all tests (prevents program output mixing with debugger output on detach)
-
✓ Project structure (PasBuild multi-module), hexagonal architecture
-
✓ OPDF shared library (
opdf_types.pas,opdf_io.pas,opdf_demangle.pas) -
✓ ELF64 section reader (
elf_reader.pas) for embedded.opdfdata -
✓ Primitive, boolean, float, enum, set type evaluators
-
✓ ShortString, AnsiString, UnicodeString, WideString evaluators
-
✓ Pointer evaluator
-
✓ Static and dynamic array evaluators (with element limit and truncation)
-
✓ Record evaluator with field access
-
✓ Class evaluator with inheritance, nil-pointer handling, dot notation
-
✓ Interface type loading, display, and evaluator (nil or type name with pointer address)
-
✓ Field-backed property evaluation; method-backed properties report gracefully
-
✓ Set type evaluator — decodes bitfield using base enum member names
-
✓ Global variable support (linker-resolved addresses)
-
✓ Local variable and parameter support (RBP-relative stack addressing)
-
✓ Nested procedure scope variable access via saved RBP chain
-
✓ Function scope records with low/high PC
-
✓ Breakpoint management (INT3 injection/restoration + single-step)
-
✓
file:linebreakpoint syntax -
✓
runcommand — fork/exec with ptrace, pause at entry point -
✓
next— step to next source line (single-step loop) -
✓
callstack/backtrace— frame traversal -
✓ Command-line argument passing to debugged programs
-
✓
verbose on|offcommand,--verbose/-vCLI flag -
✓ Linux ptrace adapter (x86_64 and i386 register structs both implemented)
-
✓ Integration test suite: 13/13 automated tests passing (pre-Phase 3 baseline)
-
✓
dbg_opdfenum insystems.inc;-gOflag inoptions.pas -
✓
dbgopdf_typemap.pas— TTypeMapper (type ID allocation) -
✓
dbgopdf.pas— TOPDFDebugWriter emitting intoal_opdfasm list -
✓ Registered in
x86_64/cputarg.pasandi386/cputarg.pas -
✓ All type handlers: ordinal, float, string, enum, set, pointer, array, record, class, interface
-
✓ All symbol handlers: global var, local var, parameter, property, function scope
-
✓ Line information: per-procedure labels, accumulated in FLineInfoList, merged at inserttypeinfo
-
✓ Embedded
.opdfELF section — linker resolves all symbol references -
✓ Cross-module type dedup via global state (
G_TypeMapper,G_EmittedTypeIDs) -
✓ Unit directory record (type 19) — indexes per-unit data sizes
-
✓ Method scopes emitted independently of parent class dedup state
-
✓ SubKind byte in
recPrimitive— derived fromdef.ordtype/tfloatdefinappenddef_ord/appenddef_float -
✓ Verified: 104-unit project loads 24K types, 1K scopes, 70K line mappings
-
External file vs embedded section — Embedded ELF section chosen. External
.opdffiles cannot carry line information because code addresses are only known after linking. All address fields use symbol references resolved by the assembler/linker. Seedocs/design-decisions.adocfor full rationale. -
ogopdf.pas → opdf_types.pas — The
ogprefix is FPC’s Output Generator convention (ogelf.pas, ogcoff.pas) and is inappropriate for the standalone opdf-lib. All units in opdf-lib follow theopdf_*naming convention. -
tpdf_type_mapper.pas → dbgopdf_typemap.pas — FPC debug subsystem units use the
dbgprefix (dbgbase.pas, dbgdwarf.pas). The type mapper is part of that subsystem. -
FPC compiler isolation —
dbgopdf.pasimports only FPC-internal units plusdbgopdf_typemap. No opdf-lib units are imported.REC_*constants are duplicated locally with{ must match opdf_types.pas }comments.
-
Arrays indexed by an enum type (e.g.
array[TDays] of String) display bounds as[0..6]rather than[Mon..Sun]— enum-keyed array bounds not yet decoded -
Nested procedure static link not modelled in OPDF — the saved RBP chain approximation works for one level of nesting only
-
set ofnon-enum ordinal types (e.g.set of 3..7) show raw bit positions, not names -
Method-backed properties with float return types (Single, Double) are not evaluated — requires
PTRACE_GETFPREGSfor XMM0 reading (Feature 8 limitation) -
Method-backed properties in imported units compiled without
-gOcannot be evaluated — getter function scope is not in OPDF; ELF symbol fallback is a future enhancement -
GetPointerSizeinpdr_opdf_adapter.pasis conditioned on the debugger’s compile-time architecture, not the debuggee’s — will be wrong when a 64-bit debugger debugs a 32-bit binary; fixed by the PointerSize prerequisite below -
Class field access inside methods now resolves bare field names via implicit Self (Feature 16); method-backed properties still require explicit
Self.PropertyNamedot notation -
elf_reader.pasonly supports ELF64; ELF32 (Linux i386) requires a format extension
The current callstack walker and variable access rely on frame pointer chains (RBP on x86_64, EBP on i386). This works for FPC-compiled code because FPC generates frame pointers by default, but breaks in several scenarios:
-
Prebuilt RTL without frame pointers: The FPC RTL is typically distributed compiled with
-O2, which may omit frame pointers. When an exception is raised inside an RTL function that has no stack frame, the RBP chain skips the calling user function entirely. The debugger sees the caller’s caller instead. This is a known issue with frame-pointer-based stack walking in Lazarus/fpdebug as well. -
Function prologue/epilogue: At the first instruction of a function (before
push rbp; mov rbp, rsp) or after the epilogue restores RBP, the frame is not established. Reading RBP at that point gives the wrong frame. -
Non-x86 architectures: ARM32 does not guarantee frame pointers. PowerPC uses the stack pointer as frame pointer with a different walking mechanism.
-
Mixed-language callstacks: C library code or system calls compiled without frame pointers break the chain.
DWARF addresses this with .debug_frame / .eh_frame unwind tables that describe frame
resolution rules at every instruction boundary. OPDF does not have an equivalent yet.
A future recUnwindInfo record type could map address ranges to frame resolution rules.
Alternatively, the debugger could fall back to reading .eh_frame sections (present even
in release builds) when no OPDF data is available for a given frame.
Priority: Low — FPC debug builds preserve frame pointers on x86/x86_64. This becomes important when tackling optimized code, non-x86 architectures, or mixed-language stacks.
Multi-unit testing with a 104-unit project (maximus) revealed scalability concerns: 3.4x type duplication (25,652 records for 7,540 unique types) and O(n) linear scans.
Solution: compiler-side cross-module type dedup + reader-side multi-header support.
FPC creates a new TOPDFDebugWriter instance per compilation unit, so dedup state
(G_TypeMapper, G_EmittedTypeIDs) is stored in global variables that persist across
modules. Each unit still gets its own OPDF header (required by linker section
concatenation), but types are only emitted once across all units. A UnitDirectory
record (type 19) is emitted at the end of the main program module to index all units.
Results: 104 units, 1.1x dedup ratio (down from 3.4x), 6.4 MB section size.
-
✓ opdf_dump diagnostic tool (Pascal, raw stream parsing, multi-header detection)
-
✓ OPDF spec updated to v0.3.0 with multi-unit design and format comparison
-
✓ Progress tracker updated with scalability work items
-
✓ Global
G_TypeMapper— consistent TypeIDs across compilation units -
✓ Global
G_EmittedTypeIDs— skip duplicate type emission across modules -
✓
TypeAlreadyEmittedguard in all 14appenddef_*methods -
✓ Per-unit byte counting via
G_ByteCounterfor unit directory -
✓
recUnitDirectory(type 19) emitted at end of main program module -
✓
OPDF_FLAG_HAS_DIRECTORYheader flag -
✓ Method scopes emitted independently of parent class dedup state
-
✓
TryReadNextHeaderinTOPDFReader— scans past linker alignment padding bytes -
✓ Multi-header loop in
TOPDFReaderAdapter.Load— processes all linker-concatenated units -
✓ Type deduplication — all type record handlers check
FTypes.Find(TypeID)before allocation -
✓
recUnitDirectoryhandling in adapter (skip) and opdf_dump (decode) -
✓ Recursion depth limit in
EvaluateVariableInfo— prevents segfault on deep class hierarchies -
✓ Stack variable address computation in
ResolveFieldAccess— fixes inspect for locals -
❏ Sorted arrays for line info and function scopes — O(log n) binary search
-
❏ Filename string interning — avoid duplicate allocations for repeated source paths
-
✓ FPC compiler rebuilt with cross-module dedup changes
-
✓ Recompile maximus with new compiler — 104 units, 24K types, 1K scopes, 70K lines
-
✓ Verify with opdf_dump: 104 headers parsed, 1.1x dedup ratio, UnitDirectory present
-
✓ Run all 18 integration tests — all passing
-
✓ Test pdr debugger against maximus: breakpoints, locals, inspect all working
Full specification: docs/feature-specs.adoc
-
✓ Add
PointerSize: BytetoTOPDFHeaderinopdf_types.pas -
✓ Emit
SizeOf(Pointer)into that field indbgopdf.pas -
✓
opdf_io.pasreader — N/A, binary format uses QWord for all address fields -
✓ Update
pdr_opdf_adapter.pasto derive pointer size from the loaded header -
✓ All integration tests passing (no binary format change — field was already emitted)
-
✓ Add
GetScopeLocals(RIP)toIDebugInfoReader/pdr_opdf_adapter.pas -
✓ Add
GetLocalVariablestopdr_engine.pas -
✓ Register
localsandlocals globalscommands inpdr_main.pas -
✓ Integration test:
test_14_locals.pas
-
✓ Add
Methods: array of StringtoTDebuggerClassinpdr_ports.pas -
✓ Add
GetInspectLines(Expr)topdr_engine.paswith per-category structured output -
✓ Register
inspect/inscommand inpdr_main.pas -
✓ Integration test:
test_15_inspect.pas
-
✓ Add
TryParseSliceparser inpdr_main.pas -
✓ Add
EvaluateArraySlice(VarName, LowIndex, HighIndex)topdr_engine.pas -
✓ Clamp out-of-bounds indices with
[WARN]message -
✓ Register
print MyArray[N..M]syntax inpdr_main.pas -
✓ Integration test:
test_16_array_slice.pas
-
✓ Add
SetVariable(VarName, Value)topdr_engine.pas -
✓ Value conversion: integer literals,
True/False, enum member names, `$`hex / `0x`hex -
✓ Write via
FProcessController.WriteMemory(PTRACE_POKEDATA on Linux) -
✓ Register
set <var> = <value>command inpdr_main.pas -
✓ Integration test:
test_17_set_variable.pas
-
❏ CLI parsing — detect
VarName[Index]syntax inpdr_main.pas; split into base name and integer index -
❏ Engine logic — look up base array variable, verify
tcArray, compute element address asbase + (index - LowBound) * ElementSize -
❏ Add
tcFloatwrite support toSetVariable(currently onlytcPrimitiveandtcEnumare handled) — parse value string viaVal, write raw bytes -
❏ Support element types:
tcPrimitive,tcEnum,tcFloat -
❏ Integration test:
test_17b_set_array_element.pas
|
Note
|
Consider whether array assignment should remain strictly per-element (SomeArray[3] = value), or whether a range form is useful — e.g. SomeArray[1..3] = (1, 2, 3) for assigning distinct values, or SomeArray[1..3] = (all 2) for flood-filling a range to a single value. The latter would be handy for initialising or resetting an array during a debug session without stepping through setup code. No decision taken yet — the per-element form is sufficient for an initial implementation.
|
-
✓ Extend
TBreakpointEntryrecord withConditionType,HitCount,CurrentHitCount -
✓ Evaluate hit-count condition in engine
Continueloop; re-arm and continue if not met -
✓ Parse
break foo.pas:N if count=Ksyntax -
✓
condition <num> count=Ncommand to set/change/remove conditions on existing breakpoints -
✓
info breakpointscommand to list all breakpoints with conditions and hit counts -
✓ Integration test:
test_20_conditional_break.pas
-
✓ Add
FDisplayListtopdr_engine.paswithAddDisplay,RemoveDisplay,ClearDisplay,EvaluateDisplayList -
✓ Print all display entries after every execution stop (continue, next, step)
-
✓ Register
display <var>,undisplay <var>,undisplay,info display -
✓ Handle out-of-scope variables gracefully — prints
(out of scope) -
✓ Integration test:
test_21_display.pas
-
✓ Add
TWatchpointType,SetWatchpoint,ClearWatchpoint,GetFiredWatchpointtoIProcessController(pdr_ports.pas) -
✓ Implement via
PTRACE_PEEKUSER/PTRACE_POKEUSERon x86_64 DR0–DR3 / DR6 / DR7 inpdr_linux_ptrace.pas -
✓ Disambiguate watchpoint vs breakpoint SIGTRAP via DR6 status register
-
✓ Add
SetWatch,RemoveWatch,GetWatchpointListtopdr_engine.pas -
✓ Display old/new values on watchpoint hit
-
✓ Register
watch,rwatch,awatch,unwatch,info watchpointscommands -
✓ Enforce 4-slot hardware limit with clear error message
-
✓ Integration test:
test_22_watchpoint.pas— 22/22 tests passing
-
✓ Add
InjectCall(MethodAddr, SelfPtr, ManagedReturn, RetValue)toIProcessController -
✓ Add
FindFunctionByName(Name, FuncInfo)toIDebugInfoReader -
✓ Implement
FindFunctionByNameinpdr_opdf_adapter.pas— linear scan of FFunctionScopes -
✓ Implement
InjectCallinpdr_linux_ptrace.pas— full x86_64 call injection:-
Save/restore all registers via
PTRACE_GETREGS/PTRACE_SETREGS -
INT3 sentinel at saved RIP for return detection
-
Red zone skip (128 bytes), 16-byte RSP alignment
-
Hidden result buffer in RSI for managed return types (AnsiString)
-
User breakpoint passthrough during injection (single-step past, re-insert)
-
Iteration limit (1000) for timeout protection
-
-
✓ Evaluate method-backed properties via
InjectCallinResolveClassProperty(pdr_typesys.pas) — explicitprint Obj.PropNametriggers call injection -
✓
FormatInjectedReturnValuehelper — formats ordinal (RAX) and AnsiString (hidden ptr) returns -
✓ Safe default:
print Objandinspectshow<getter: MethodName>without calling — avoids side effects; matches GDB/LLDB behaviour -
✓
inspectshows[use 'print Obj.Prop' to evaluate]hint for method properties -
✓ Updated
test_05_propertiesexpected output for getter annotations -
✓ New integration test:
test_24_method_properties.pas— AnsiString + Integer getters -
✓ Updated output filter in
run_tests.shto support dot-notation variable names -
✓ 24/24 integration tests passing
-
❏ Write
pdr_expr_preproc.pas— tokeniser resolving dot notation and[N]indexing -
❏ Integrate
fpexprpars(FPC unitpackages/fcl-base/src/fpexprpars.pp) as eval core -
❏ Register variable resolver callback using
TTypeSystem.EvaluateVariable -
❏ Workaround for missing
div/shl/shrin fpexprpars (rewrite in pre-processor) -
❏ Open upstream FPC issue and submit patch for
div/shl/shrin fpexprpars -
❏ Enable
print <expr>for compound expressions -
❏ Integration test:
test_22_expression.pas
-
❏ Extend
REC_RECORDinopdf_types.paswith variant group descriptors -
❏ Update
dbgopdf.pasappenddef_recordto emit variant fields -
❏ Add
TVariantRecordEvaluatortopdr_typesys.pas -
❏ Integration test:
test_23_variant_record.pas
-
❏ Define
recVariantrecord type inopdf_types.pas -
❏ Emit
recVariantindbgopdf.pasfortvariantdef -
❏ Add
TOPDFReader.ReadVariantinopdf_io.pas -
❏ Parse and cache variant types in
pdr_opdf_adapter.pas -
❏ Add
TVariantEvaluatortopdr_typesys.pas(decode VarType discriminant + value) -
❏ Integration test:
test_variant_types.pas
-
❏ Hardcode
TList<T>,TObjectList<T>,TDictionary<K,V>layout knowledge -
❏ Recognise container type names by prefix in
pdr_typesys.pas -
❏ Integration test:
test_24_generics.pas
-
✓ Add ELF
.symtabsymbol lookup (FindSymbolAddressinelf_reader.pas) -
✓ Set internal breakpoint on
fpc_raiseexceptionat program launch -
✓ Read exception class name from VMT (
vmtClassNameat offset +24) -
✓ Read
FMessageAnsiString (offset +16 with_MonitorData, fallback +8) -
✓ Display:
Exception: ClassName — 'message'with source location -
✓ Add
catch/nocatchCLI commands to enable/disable break on raise -
✓ Disambiguate internal breakpoint from user breakpoints in Continue
-
✓ Integration test:
test_23_exception.pas— 23/23 tests passing
-
✓ Add
recConstant = 20record type to OPDF format (opdf_types.pas) -
✓ Add
TConstantKindenum:ckOrd,ckString,ckReal,ckNil,ckWideStr -
✓ Add
TDefConstantpacked record with embedded value bytes -
✓ Add
WriteConstant/ReadConstanttoopdf_io.pas -
✓ Implement
appendsym_constindbgopdf.pas— emits constants forconstord,conststring,constreal,constnil,constwstring -
✓ Add
TConstantInforecord andFindConstantmethod toIDebugInfoReader(pdr_ports.pas) -
✓ Add
FConstantshash list with loading and lookup inpdr_opdf_adapter.pas -
✓ Add constant fallback in
TTypeSystem.EvaluateVariablewith Boolean/Char display refinement -
✓ Integration test:
test_25_constants.pas -
❏ Extend
appendsym_constfor remaining constant kinds:constset,constguid,constpointer,constresourcestring,constwresourcestring -
❏ Add enum constant display (resolve member name from TypeID)
-
✓ Fix
StepLine(step over) — uses function scope address range (FindFunctionByAddress) instead of 100-line range heuristic -
✓ Implement
StepInto— loopsPTRACE_SINGLESTEPuntil source line changes (FindLineByAddress) -
✓ Wire
step/stoStepIntoandnext/ntoStepLinein CLI -
✓ Gate ptrace adapter
[INFO] Step completeon gVerbose to prevent noise during StepInto loops -
✓ Fix
Continue;name collision — FPC resolves bareContinue;insideTDebuggerEngine.StepLinetoself.Continue(the method) instead of the loop control keyword; restructured loop to useif-elsechains -
✓ Integration test:
test_26_step_over.pas— step over a procedure call stays in caller -
✓ Integration test:
test_27_step_into.pas— step into a function call descends into callee
-
✓ Emit
SelfasrecLocalVarindbgopdf.pas— relax thevo_is_hidden_paraskip for method Self parameters only -
✓ Add Self-field resolution tier in
TTypeSystem.EvaluateVariable(pdr_typesys.pas) — when a bare name is not found in locals/globals/constants, look upSelfin scope, resolve its class type, and search fields (with inheritance chain walk) -
✓ Add Self-field fallback in
TDebuggerEngine.GetInspectLines(pdr_engine.pas) —inspect FFontManagerinside a method resolves via Self and renders the full structured view -
❏ Integration test:
print FFontManagerinside a method resolves the class field -
❏ Verify: local variables shadow class fields of the same name
-
✓ Add
TOPDFPrimitiveSubKindenum andSubKind: Bytefield toTDefPrimitive(opdf_types.pas) -
✓ Update
WritePrimitiveto accept and write SubKind (opdf_io.pas) -
✓ Emit SubKind from FPC compiler — derive from
def.ordtypeinappenddef_ord, emitSUBKIND_FLOATinappenddef_float(dbgopdf.pas) -
✓ Read SubKind in adapter, use for
tcFloatvstcPrimitivecategorisation (pdr_opdf_adapter.pas) -
✓ Add
SubKind: BytetoTTypeInfo(pdr_ports.pas) -
✓ Replace all 5 name-matching heuristics with SubKind-based checks (
pdr_typesys.pas) -
✓ Display SubKind in
opdf_dumpoutput (opdf_dump.pas) -
✓ Update OPDF specification with SubKind byte and value table (
opdf-specification.adoc) -
✓ All 27 integration tests pass unchanged
-
❏ Extend
LocationExprencoding: value3= register-allocated -
❏ Update
dbgopdf.pasappendsym_localvarto emitLocationExpr = 3forLOC_REGISTER -
❏ Update
EvaluateVariableInfoto read from live register state forLocationExpr = 3 -
❏ Increment
TOPDFHeader.Version; updateopdf-specification.adoc
-
❏ Extend
elf_reader.pasfor ELF32 (Linux i386 support) -
❏ Write
pe_reader.pas— PE/COFF section extraction (Windows binaries) -
❏ Write
pdr_windows_debug.pas—IProcessControllervia Windows debug API -
❏ Wire format dispatch in
pdr_opdf_adapter.pas(ELF vs PE detection) -
❏ Windows i386: i386
CONTEXTstruct variant inpdr_windows_debug.pas -
❏ macOS: Mach-O section reader + Mach port process controller (deferred)
opdf-lib/ → core OPDF format, I/O, ELF reader, demangling pdr-core/ → engine, type system, evaluators, port interfaces pdr-adapters/ → Linux ptrace, OPDF reader adapter, arch helpers pdr-cli/ → command-line interface (REPL) tools/ → opdf_dump (Pascal diagnostic tool for .opdf section analysis)
dbgopdf.pas → OPDF debug writer (emits into al_opdf asm list) dbgopdf_typemap.pas → Type ID allocation (TTypeMapper) aasmdata.pas → al_opdf enum in TAsmListType systems.inc → dbg_opdf enum entry options.pas → -gO flag handling x86_64/cputarg.pas → dbgopdf registration i386/cputarg.pas → dbgopdf registration
test_01_primitives → Integer and Boolean variables test_01_loop → Loop and breakpoint testing test_02_breakpoint_next → Break and next commands test_03_strings → All string types test_04_classes → Class instances and fields test_05_properties → Properties with getters/setters test_06_local_variables → Stack-based locals test_07_variable_shadowing → Scope resolution test_08_static_arrays → Static array bounds test_09_dynamic_arrays → Dynamic array length/elements test_10_arguments → Function arguments test_11_callstack → Stack traces test_12_teaser_demo → Nested scope (OuterProcedure / InnerNested) test_13_sets → Set type display ([Mon, Tue, Wed, Thu, Fri]) test_14_locals → locals command: in-scope variable listing test_15_inspect → inspect command: record field layout test_16_array_slice → print MyArray[N..M] slice display with clamping test_17_set_variable → set command: modify Counter and MyFlag in-process test_18_inspect_class_intf → inspect command: class + interface with methods test_19_nested_scope → nested procedure scoping: DeclIndex-based visibility test_20_conditional_break → conditional breakpoint: hit-count form (count=7 in loop) test_21_display → display command: auto-print Iter and Sum across continues test_22_watchpoint → hardware watchpoints: DR0-DR3 write/read-write detection test_23_exception → break on exception raise with class name and message test_24_method_properties → method-backed property evaluation via call injection test_25_constants → compile-time constant display (Integer, Boolean, Char, Real, String, UTF-8) test_26_step_over → step over: next skips called procedure, stays in caller test_27_step_into → step into: step descends into called function body
# Build all modules (standalone debugger)
cd /data/devel/opdebugger
pasbuild compile
# Build FPC compiler with OPDF support
cd /data/devel/fpc-3.3.1/src
make -C compiler cycle# Compile test with FPC OPDF support (use ppcx64 directly, not fpc driver)
/data/devel/fpc-3.3.1/x86_64-linux/lib/fpc/3.3.1/ppcx64 \
@/data/devel/fpc-3.3.1/x86_64-linux/lib/fpc/3.3.1/fpc.cfg \
-gO test.pas
# Run debugger on a test binary
../../pdr-cli/target/pdr test_01_primitives
# Run full automated test suite
bash run_tests.sh
# Run single test
bash run_tests.sh test_01_primitivesrun Start program (pauses at entry)
break file.pas:22 Set breakpoint by file:line
break 0x401000 Set breakpoint by hex address
break MyVar Set breakpoint by variable name
break <loc> if count=N Conditional breakpoint (fire on Nth hit)
condition <num> count=N Set/change hit-count condition
condition <num> Remove condition (make unconditional)
info breakpoints List all breakpoints with conditions
display <expr> Auto-print expression on every stop
undisplay <expr> Remove from auto-display list
undisplay Remove all display entries
info display List registered display expressions
continue / c Resume execution
next / n Step over: next source line, skipping into calls
step / s Step into: next source line, descending into calls
print <var> Print variable value
print <var>.<field> Dot notation for class/record fields
print <arr>[N..M] Array slice — elements N to M inclusive
locals List all in-scope variables with values
locals globals Include global variables
inspect <var> Structured view: fields, properties, methods
set <var> = <value> Assign value to a primitive or enum variable
callstack / cs Show call stack
delete <num> Remove breakpoint
verbose on|off Toggle verbose/debug output
quit Exit debugger