summaryrefslogtreecommitdiffstats
AgeCommit message (Collapse)AuthorFilesLines
2025-09-07Manually uninstall breakpoints on process forkHEADmasterMatt Hunter1-0/+11
Previously, there was a bug on PTRACE_EVENT_FORK in which the forked child process inherits all installed breakpoints due to their interrupt instructions being resident in memory at the time of the fork, but the debugger initializes the new process model with an empty list of breakpoints. There are some differing opinions on what the correct behavior ought to be here, but at a minimum these two realities must be brought into sync to prevent data corruption or any process crash of the fork child. For the time being, manually "uninstall" the residual breakpoint interrupts from a newly forked child that we attach to, leaving it with no breakpoints of any kind. Process model initialization in the debugger is left as-is. Signed-off-by: Matt Hunter <m@lfurio.us>
2025-09-07Discard breakpoint list on process execveMatt Hunter1-0/+2
On exec, the program image and address space completely changes, so any previously established breakpoints going forward are meaningless. Even if we are re-execing the same actual program, ASLR may invalidate the addresses of BPs, let alone if the program is modified/recompiled. The act of performing the exec already "uninstalls" any breakpoints by reloading the memory space, adapt to this by simply freeing our list of managed breakpoints from the debugger, without any additional processing. Signed-off-by: Matt Hunter <m@lfurio.us>
2025-09-07Allow multiple modifier chars in breakpoint CLIMatt Hunter1-9/+13
Signed-off-by: Matt Hunter <m@lfurio.us>
2025-09-07Merge branch 'arm32'Matt Hunter7-38/+257
Add initial 32-bit ARM support and additionally build out internal breakpoint design to allow the use of single-step oriented breakpoints. * arm32: Always prune step breakpoints when uninstalling from memory Update detect_breakpoint() to better handle single stepping Add architecture-specific single step support Add 32-bit ARM architecture params
2025-09-07Always prune step breakpoints when uninstalling from memoryMatt Hunter1-1/+6
On completion of an initial single step, we can and should discard these breakpoints, even though the thread may not be "stopping" and go on to continue in free-run. They have served their purpose at this point and we would like to avoid any other thread encountering them. Also, whenever uninstall_breakpoints() is called, it is because we are cycling a process's threads and are about to run resume_threads() which currently does the work of re-computing a thread's step breakpoints if a previous single step was interrupted, whether or not the step breakpoints for that instant have already been figured. So this also addresses a bug where one thread, with repeatedly interrupted single steps, would accumulate more and more redundant breakpoint entries until it was finally able to proceed and eventually stop. Signed-off-by: Matt Hunter <m@lfurio.us>
2025-09-07Update detect_breakpoint() to better handle single steppingMatt Hunter1-18/+30
A stopped thread should sometimes restart, even if a breakpoint interrupted a single step. detect_breakpoint() and its interaction with wait_thread() is updated such that any restart during a single step scenario properly "requeues" the thread's run intent, by preserving the doing/donext flags. Furthermore, detect_breakpoint() ditches its call to get_breakpoint() and considers any and all breakpoints impacting the current thread PC, since they may each suggest different restarting requirements. In effect, the thread will only remain stopped if at least one relevant breakpoint allows it to do so. This reverts commit 5589a9e3afd5 ("Ignore breakpoints during singlestep"). Signed-off-by: Matt Hunter <m@lfurio.us>
2025-09-07Add architecture-specific single step supportMatt Hunter6-9/+208
ARM 32-bit is the first platform added to misplays which lacks underlying hardware support for single step traps - so the kernel does not implement PTRACE_SINGLESTEP in this case. We will work around this in a similar way as gdb does and how the kernel used to do it until 2011. arm_singlestep() implements logic which disassembles the program's current instruction and analyzes it to determine all possible next locations - eg: the next instruction in memory, or the jump target of a branch instruction, etc. This logic is dynamically dispatched by the debugger core if an ARM build is running in 32-bit mode. arm_singlestep() uses breakpoints to stop execution at it's computed next locations. However, misplays is currently very careful about controling the use of breakpoints in order to avoid issues with thread single steps - so a new flag (called "step") is added to breakpoints to enable the debugger to selectively install this subset of breakpoints for each thread's single step action, and more or less keep treating thread free-run as normal. install_breakpoints() is updated to take a "step" parameter to control which set of breakpoints is installed at any given time. resume_threads() is updated to perform this new single step dynamic dispatch, and manage the installation of step breakpoints. add_breakpoint() is also given a "step" parameter. This initializes the flag for the new breakpoint, but crucially is used to sort the new breakpoint into the process breakpoint list. Since step breakpoints will always be installed first, prioritize them in the list so that uninstall_breakpoints() doesn't corrupt memory when it runs the list backward to remove them. Signed-off-by: Matt Hunter <m@lfurio.us>
2025-09-07Add 32-bit ARM architecture paramsMatt Hunter1-10/+13
Signed-off-by: Matt Hunter <m@lfurio.us>
2025-07-26Print gdb message on startup instead of waiting silentlyMatt Hunter1-0/+1
Signed-off-by: Matt Hunter <m@lfurio.us>
2025-07-26Fix possible segfault in dbg_detachMatt Hunter1-1/+3
If dbg_attach fails, it calls this function to clean up before the process in added to the main process list, so list_remove() is invalid. Signed-off-by: Matt Hunter <m@lfurio.us>
2024-05-08Only update ncurses display on activity or keypressMalfurious5-14/+32
Previously, the test UI logic would constantly regenerate and print the screen's contents every iteration of the main processing loop to naively ensure that changes to the underlying system were reflected immediately. Sometimes, this would result in a screen flicker due to the rapid clearing and printing. This makes the UI a bit smarter about when refreshes occur, by monitoring activity results from the debugger and console modules in addition to user input. This should improve the screen flicker performance. This also addresses an issue selecting text on the screen, which was previously not possible due to the rapid refreshing as well. Signed-off-by: Malfurious <m@lfurio.us>
2024-05-08Add 64-bit ARM architecture constantsMalfurious2-0/+47
Signed-off-by: Malfurious <m@lfurio.us>
2024-05-08Parameterize architecture-specific detailsMalfurious6-32/+178
Abstract architecture details into architecture.h and add x86 constants. This is slightly complicated by the fact that 64-bit hosts can run 32-bit code, so we do still need to resolve some values dynamically. The architecture_info() function is intented to address this, and performs parameter lookups based on the current state of the guest process. Resolving values on a per-process-state basis is important due to the process model under Linux. If we fork to debug a 32-bit program, the forked process will be native 64-bit until the execve system call. And of course, the process is then free to exec anything it likes later on as well. Signed-off-by: Malfurious <m@lfurio.us>
2024-05-08Remove call to close_range() during process forkMalfurious1-1/+1
I don't think this is strictly necessary, just seemed like a good idea. However, this function doesn't seem to be available on my test ARM system, so it is removed for compatibility. Signed-off-by: Malfurious <m@lfurio.us>
2024-05-08Show each active breakpoint one per lineMalfurious1-2/+1
Signed-off-by: Malfurious <m@lfurio.us>
2024-05-08Add additional list operationsMalfurious2-4/+28
Add list functions which can efficiently cut down on some bolierplate. The rest of the code will eventually be cleaned to make use of them. Signed-off-by: Malfurious <m@lfurio.us>
2024-04-27Fix removal of temporary breakpoints when rapidly restarting threadMalfurious2-9/+11
This bug would occur when the debugger keeps rapidly hitting a breakpoint and restarting execution (and the breakpoint is temporary / one-time). For example, stepping over a long recursive call. It would be possible for the user to manually interrupt execution at the precise moment that the debugee was returning from a single step over the breakpoint. In this scenario, the thread would correctly remain stopped as requested, however the temporary breakpoint would incorrectly remain in the breakpoint list. The cause of this issue is that uninstall_breakpoints only considered removing temporaries if they were currently installed for use. This makes sense, as we have used the b->installed flag as a sort of check to see if we have YET installed the breakpoint (rather than "is it STILL installed?") to ensure that we don't remove it too soon. The more accurate logic here is to acctually check whether the breakpoint has EVER been installed and only then consider it for removal if it is temporary. This fixes the case in question without breaking behavior when performing an initial run single step. Signed-off-by: Malfurious <m@lfurio.us>
2024-04-27Show breakpoint limiters in the test UIMalfurious1-2/+3
Display the value of active breakpoint threads, target stack frames, and enable status. Signed-off-by: Malfurious <m@lfurio.us>
2024-04-24Merge branch 'threads'Malfurious5-373/+905
This branch adds initial support for multithreaded targets, as well as forking and exec syscalls. All of the bugs from initial testing are fixed so far. * threads: (25 commits) Don't spin waiting to interrupt zombie process Allow termination and exec events to propagate immediately Implement support for PTRACE_EVENT_FORK and ui Handle PTRACE_EVENT_EXIT to capture a final state snapshot Detect out-of-band thread exec state changes to prevent deadlock Enable user creation of thread-specific breakpoints Add orig_rax to register display Tweak SCHEDULER_DELAY for use with installing breakpoints Ignore breakpoints during singlestep Fix bug with cleaning temporary breakpoints Independent thread control refactor Multithread version 3 Add strict_strtoul Prevent lingering traps after detach Handle PTRACE_EVENT_EXEC Workaround SIGSTOP on child process startup setpgid is redundant with setsid and causes an error Display name of pending signal dbg_realcont for testing purposes Display installed status of breakpoints ...
2024-04-24Don't spin waiting to interrupt zombie processMalfurious1-1/+1
Targets can get into this state, for example, when receiving a killing signal. Signed-off-by: Malfurious <m@lfurio.us>
2024-04-24Allow termination and exec events to propagate immediatelyMalfurious1-3/+1
Signed-off-by: Malfurious <m@lfurio.us>
2024-04-24Implement support for PTRACE_EVENT_FORK and uiMalfurious3-56/+78
Signed-off-by: Malfurious <m@lfurio.us>
2024-04-24Handle PTRACE_EVENT_EXIT to capture a final state snapshotMalfurious1-2/+12
Also, it is now possible for interrupt_all_threads to fail to stop threads in uninterruptable sleep (eg: the main thread during execve). This may happen in more general cases as well, but it is now common enough in that case to worry about. Signed-off-by: Malfurious <m@lfurio.us>
2024-04-24Detect out-of-band thread exec state changes to prevent deadlockMalfurious1-12/+41
Signed-off-by: Malfurious <m@lfurio.us>
2024-04-24Enable user creation of thread-specific breakpointsMalfurious1-0/+5
Signed-off-by: Malfurious <m@lfurio.us>
2024-04-24Add orig_rax to register displayMalfurious1-0/+1
Signed-off-by: Malfurious <m@lfurio.us>
2024-04-24Tweak SCHEDULER_DELAY for use with installing breakpointsMalfurious2-2/+7
Signed-off-by: Malfurious <m@lfurio.us>
2024-04-24Ignore breakpoints during singlestepMalfurious1-20/+13
Due to new independent thread control, it is now possible and likely that breakpoints will be installed before singlesteps are waited upon to be completed. also clean detect_breakpoint with get_breakpoint. Signed-off-by: Malfurious <m@lfurio.us>
2024-04-24Fix bug with cleaning temporary breakpointsMalfurious1-9/+10
dont remove them before initial use Signed-off-by: Malfurious <m@lfurio.us>
2024-04-24Independent thread control refactorMalfurious3-220/+203
Signed-off-by: Malfurious <m@lfurio.us>
2024-04-24Multithread version 3Malfurious3-319/+330
Signed-off-by: Malfurious <m@lfurio.us>
2024-04-24Add strict_strtoulMalfurious2-0/+7
Signed-off-by: Malfurious <m@lfurio.us>
2024-04-24Prevent lingering traps after detachMalfurious1-0/+3
There can sometimes be a pending SIGTRAP when we resume a thread. This is usually due to interrupting a hung single-step. If this trap is hit after the debugger leaves, the original process will crash. This is a quick workaround to attempt to consume such traps ourselves before detaching. Signed-off-by: Malfurious <m@lfurio.us>
2024-04-24Handle PTRACE_EVENT_EXECMalfurious1-0/+29
Signed-off-by: Malfurious <m@lfurio.us>
2024-04-24Workaround SIGSTOP on child process startupMalfurious2-2/+8
The debugger design prefers to use PTRACE_SEIZE instead of PTRACE_ATTACH, due to the simpler thread control semantics that are available. However, to utilize the same featureset for forked processes, we can no longer use PTRACE_TRACEME to guarantee that the child becomes a tracee before it execs into the target program. Manually raising SIGSTOP to act as a synchronization point is problematic for a couple reasons: - We need to detect whether the special SIGSTOP was or was not yet encountered by the time our debugger module attaches and interrupts the thread. This complicates the dance of input controls to ensure we are at the exec (and nowhere else) when the real user takes over the controls. - The injection of an extra signal circumvents the benefits we hope to leverage by using the PTRACE_SEIZE semantics. We can no longer assume that all incoming signals are genuine. For the time being, sleep in the newly forked child for the scheduler delay period. This is not bullet-proof, but tends to allow the debugger module enough time to actually seize the thread before anything interesting happens. At this point a single dbg_cont() will cause the child to arrive and stop at the user's exec. Signed-off-by: Malfurious <m@lfurio.us>
2024-04-24setpgid is redundant with setsid and causes an errorMalfurious1-1/+0
Signed-off-by: Malfurious <m@lfurio.us>
2024-04-24Display name of pending signalMalfurious1-1/+2
Signed-off-by: Malfurious <m@lfurio.us>
2024-04-24dbg_realcont for testing purposesMalfurious3-0/+23
Signed-off-by: Malfurious <m@lfurio.us>
2024-04-24Display installed status of breakpointsMalfurious1-1/+1
Signed-off-by: Malfurious <m@lfurio.us>
2024-04-24(Un)install breakpoints via specific threadMalfurious1-15/+15
We need to perform these changes with a thread ID that is known to be in ptrace stop. This is a requirement of the API even though the memory change is seen by all threads of the guest process. Signed-off-by: Malfurious <m@lfurio.us>
2024-04-24Don't drop temporary breakpoints when execution is to be restartedMalfurious1-9/+16
Signed-off-by: Malfurious <m@lfurio.us>
2024-04-24Fix capture_state edge casesMalfurious1-5/+21
Use `th->state == NULL` as an indicator that each thread's state is capturable, discard use of the `all` parameter. Signed-off-by: Malfurious <m@lfurio.us>
2024-04-24Multithread version 2Malfurious4-538/+379
Signed-off-by: Malfurious <m@lfurio.us>
2024-04-24Multithread version 1Malfurious5-283/+825
Signed-off-by: Malfurious <m@lfurio.us>
2023-07-08Initial debugger core and test UIMalfurious4-47/+612
This is vaguely competent at tracing single-threaded programs. Vi-like keybinds defined in misplays.c. Signed-off-by: Malfurious <m@lfurio.us>
2023-07-08Implement trivial linked listMalfurious3-0/+43
* Bring-your-own-node (generic / zero allocations) * Doubly-linked and circular, forward and backward traversable * Random insert/removal in constant time * All operations are no-fail * [Some type safety concessions though] Signed-off-by: Malfurious <m@lfurio.us>
2023-07-07Add panel clear helperMalfurious2-0/+5
Signed-off-by: Malfurious <m@lfurio.us>
2023-07-07Add malloc wrapperMalfurious2-0/+11
Abort on allocation failure. This is mostly done as a formality, as Linux tends to over-commit memory anyway. In the event of most failures, we won't have a reasonable recovery either. Signed-off-by: Malfurious <m@lfurio.us>
2023-07-06Rename curshelpers unit to 'helpers'Malfurious5-5/+4
Signed-off-by: Malfurious <m@lfurio.us>
2023-07-05Add CMake build systemMalfurious2-0/+39
Signed-off-by: Malfurious <m@lfurio.us>