1//===-- ptrace_example.c --------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include <asm/ptrace.h>
10#include <linux/elf.h>
11#include <stdint.h>
12#include <stdio.h>
13#include <sys/prctl.h>
14#include <sys/ptrace.h>
15#include <sys/uio.h>
16#include <sys/wait.h>
17#include <unistd.h>
18
19// The demo program shows how to do basic ptrace operations without lldb
20// or lldb-server. For the purposes of experimentation or reporting bugs
21// in kernels.
22//
23// It is AArch64 Linux specific, adapt as needed.
24//
25// Expected output:
26// Before breakpoint
27// After breakpoint
28
29void inferior() {
30 if (ptrace(request: PTRACE_TRACEME, 0, 0, 0) < 0) {
31 perror(s: "ptrace");
32 return;
33 }
34
35 printf(format: "Before breakpoint\n");
36
37 // Go into debugger. Instruction replaced with nop later.
38 // We write 2 instuctions because POKETEXT works with
39 // 64 bit values and we don't want to overwrite the
40 // call to printf accidentally.
41 asm volatile("BRK #0 \n nop");
42
43 printf(format: "After breakpoint\n");
44}
45
46void debugger(pid_t child) {
47 int wait_status;
48 // Wait until it hits the breakpoint.
49 wait(stat_loc: &wait_status);
50
51 while (WIFSTOPPED(wait_status)) {
52 if (WIFEXITED(wait_status)) {
53 printf(format: "inferior exited normally\n");
54 return;
55 }
56
57 // Read general purpose registers to find the PC value.
58 struct user_pt_regs regs;
59 struct iovec io;
60 io.iov_base = &regs;
61 io.iov_len = sizeof(regs);
62 if (ptrace(PTRACE_GETREGSET, child, NT_PRSTATUS, &io) < 0) {
63 printf(format: "getregset failed\n");
64 return;
65 }
66
67 // Replace brk #0 / nop with nop / nop by writing to memory
68 // at the current PC.
69 uint64_t replace = 0xd503201fd503201f;
70 if (ptrace(request: PTRACE_POKETEXT, child, regs.pc, replace) < 0) {
71 printf(format: "replacing bkpt failed\n");
72 return;
73 }
74
75 // Single step over where the brk was.
76 if (ptrace(request: PTRACE_SINGLESTEP, child, 0, 0) < 0) {
77 perror(s: "ptrace");
78 return;
79 }
80
81 // Wait for single step to be done.
82 wait(stat_loc: &wait_status);
83
84 // Run to completion.
85 if (ptrace(request: PTRACE_CONT, child, 0, 0) < 0) {
86 perror(s: "ptrace");
87 return;
88 }
89
90 // Wait to see that the inferior exited.
91 wait(stat_loc: &wait_status);
92 }
93}
94
95int main() {
96 pid_t child = fork();
97
98 if (child == 0)
99 inferior();
100 else if (child > 0)
101 debugger(child);
102 else
103 return -1;
104
105 return 0;
106}
107

source code of lldb/examples/ptrace_example.c