github.com/ks888/tgo@v0.0.0-20190130135156-80bf89407292/debugapi/client_linux_test.go (about) 1 package debugapi 2 3 import ( 4 "os" 5 "os/exec" 6 "reflect" 7 "runtime" 8 "syscall" 9 "testing" 10 11 "github.com/ks888/tgo/testutils" 12 "golang.org/x/sys/unix" 13 ) 14 15 func TestMain(m *testing.M) { 16 runtime.LockOSThread() 17 os.Exit(m.Run()) 18 } 19 20 func TestCheckInterface(t *testing.T) { 21 var _ client = newRawClient() 22 var _ client = NewClient() 23 } 24 25 func TestClientProxy(t *testing.T) { 26 client := NewClient() 27 _ = client.LaunchProcess(testutils.ProgramInfloop) 28 defer client.DetachProcess() 29 30 _ = client.WriteMemory(testutils.InfloopAddrMain, []byte{0xcc}) 31 event, err := client.ContinueAndWait() 32 if err != nil { 33 t.Fatalf("failed to continue and wait: %v", err) 34 } 35 if event.Type != EventTypeTrapped { 36 t.Fatalf("unexpected event: %#v", event.Type) 37 } 38 } 39 40 func TestLaunchProcess(t *testing.T) { 41 client := newRawClient() 42 err := client.LaunchProcess(testutils.ProgramInfloop) 43 if err != nil { 44 t.Fatalf("failed to launch process: %v", err) 45 } 46 defer client.DetachProcess() 47 48 // Do some ptrace action for testing 49 pid := client.tracingThreadIDs[0] 50 _, err = syscall.PtracePeekData(pid, uintptr(testutils.InfloopAddrMain), []byte{0x0}) 51 if err != nil { 52 t.Errorf("can't peek process' data: %v", err) 53 } 54 } 55 56 func TestLaunchProcess_ProgramNotExist(t *testing.T) { 57 client := newRawClient() 58 err := client.LaunchProcess("notexist") 59 if err == nil { 60 t.Fatal("error is not returned") 61 } 62 } 63 64 func TestAttachProcess(t *testing.T) { 65 cmd := exec.Command(testutils.ProgramInfloop) 66 _ = cmd.Start() 67 68 client := newRawClient() 69 pid := cmd.Process.Pid 70 err := client.AttachProcess(pid) 71 if err != nil { 72 t.Fatalf("failed to attach process: %v", err) 73 } 74 defer func() { 75 client.DetachProcess() 76 client.killProcess() 77 }() 78 79 // Do some ptrace action for testing 80 _, err = syscall.PtracePeekData(pid, uintptr(testutils.InfloopAddrMain), []byte{0x0}) 81 if err != nil { 82 t.Errorf("can't peek process' data: %v", err) 83 } 84 } 85 86 func TestAttachProcess_SignaledBeforeAttach(t *testing.T) { 87 cmd := exec.Command(testutils.ProgramInfloop) 88 _ = cmd.Start() 89 90 pid := cmd.Process.Pid 91 proc, _ := os.FindProcess(pid) 92 _ = proc.Signal(unix.SIGUSR1) 93 94 client := newRawClient() 95 err := client.AttachProcess(pid) 96 if err == nil { 97 t.Fatalf("error is not returned") 98 } 99 100 client.DetachProcess() 101 client.killProcess() 102 } 103 104 func TestAttachProcess_NonExistPid(t *testing.T) { 105 cmd := exec.Command(testutils.ProgramInfloop) 106 _ = cmd.Start() 107 pid := cmd.Process.Pid 108 // make sure the pid doesn't exist 109 proc, _ := os.FindProcess(pid) 110 proc.Kill() 111 112 client := newRawClient() 113 err := client.AttachProcess(pid) 114 if err == nil { 115 t.Fatalf("error is not returned") 116 } 117 } 118 119 func TestDetachProcess(t *testing.T) { 120 client := newRawClient() 121 err := client.LaunchProcess(testutils.ProgramInfloop) 122 if err != nil { 123 t.Fatalf("failed to launch process: %v", err) 124 } 125 defer client.DetachProcess() 126 127 if err := client.DetachProcess(); err != nil { 128 t.Fatalf("failed to detach process: %v", err) 129 } 130 131 // Do some ptrace action for testing 132 pid := client.tracingThreadIDs[0] 133 _, err = syscall.PtracePeekData(pid, uintptr(testutils.InfloopAddrMain), []byte{0x0}) 134 if err == nil { 135 t.Errorf("error is not returned") 136 } 137 } 138 139 func TestReadMemory(t *testing.T) { 140 client := newRawClient() 141 _ = client.LaunchProcess(testutils.ProgramInfloop) 142 defer client.DetachProcess() 143 144 expected := []byte{0x64, 0x48, 0x8b} 145 buff := make([]byte, len(expected)) 146 err := client.ReadMemory(testutils.InfloopAddrMain, buff) 147 if err != nil { 148 pid := client.tracingThreadIDs[0] 149 t.Fatalf("failed to read memory (pid: %d): %v", pid, err) 150 } 151 152 if !reflect.DeepEqual(buff, expected) { 153 t.Errorf("Unexpected content: %v", buff) 154 } 155 } 156 157 func TestWriteMemory(t *testing.T) { 158 client := newRawClient() 159 _ = client.LaunchProcess(testutils.ProgramInfloop) 160 defer client.DetachProcess() 161 162 softwareBreakpoint := []byte{0xcc} 163 err := client.WriteMemory(testutils.InfloopAddrMain, softwareBreakpoint) 164 if err != nil { 165 pid := client.tracingThreadIDs[0] 166 t.Fatalf("failed to write memory (pid: %d): %v", pid, err) 167 } 168 } 169 170 func TestReadRegisters(t *testing.T) { 171 client := newRawClient() 172 _ = client.LaunchProcess(testutils.ProgramInfloop) 173 defer client.DetachProcess() 174 175 pid := client.tracingThreadIDs[0] 176 regs, err := client.ReadRegisters(pid) 177 if err != nil { 178 t.Fatalf("failed to read registers (pid: %d): %v", pid, err) 179 } 180 181 if regs.Rip == 0 { 182 t.Errorf("emptyr rip") 183 } 184 } 185 186 func TestWriteRegisters(t *testing.T) { 187 client := newRawClient() 188 _ = client.LaunchProcess(testutils.ProgramInfloop) 189 defer client.DetachProcess() 190 191 pid := client.tracingThreadIDs[0] 192 regs, _ := client.ReadRegisters(pid) 193 regs.Rip = uint64(testutils.InfloopAddrMain) 194 err := client.WriteRegisters(pid, regs) 195 if err != nil { 196 t.Fatalf("failed to write registers (pid: %d): %v", pid, err) 197 } 198 } 199 200 func TestReadTLS(t *testing.T) { 201 client := newRawClient() 202 err := client.LaunchProcess(testutils.ProgramInfloop) 203 if err != nil { 204 t.Fatalf("failed to launch process: %v", err) 205 } 206 defer client.DetachProcess() 207 208 _ = client.WriteMemory(testutils.InfloopAddrMain, []byte{0xcc}) 209 _, _ = client.ContinueAndWait() 210 211 gAddr, err := client.ReadTLS(client.trappedThreadIDs[0], -8) 212 if err != nil { 213 t.Fatalf("failed to read tls: %v", err) 214 } 215 if gAddr == 0 { 216 t.Errorf("empty addr") 217 } 218 } 219 220 func TestContinueAndWait_Trapped(t *testing.T) { 221 client := newRawClient() 222 _ = client.LaunchProcess(testutils.ProgramInfloop) 223 defer client.DetachProcess() 224 225 _ = client.WriteMemory(testutils.InfloopAddrMain, []byte{0xcc}) 226 event, err := client.ContinueAndWait() 227 if err != nil { 228 t.Fatalf("failed to continue and wait: %v", err) 229 } 230 if event.Type != EventTypeTrapped { 231 t.Fatalf("unexpected event: %#v", event.Type) 232 } 233 stoppedPID := event.Data.([]int) 234 pid := client.tracingThreadIDs[0] 235 if stoppedPID[0] != pid { 236 t.Fatalf("unexpected process is stopped: %d", stoppedPID[0]) 237 } 238 } 239 240 func TestContinueAndWait_Exited(t *testing.T) { 241 client := newRawClient() 242 _ = client.LaunchProcess(testutils.ProgramHelloworld) 243 defer client.DetachProcess() 244 245 for { 246 event, err := client.ContinueAndWait() 247 if err != nil { 248 t.Fatalf("failed to continue and wait: %v", err) 249 } 250 if event.Type == EventTypeExited { 251 break 252 } 253 } 254 } 255 256 func TestContinueAndWait_Signaled(t *testing.T) { 257 client := newRawClient() 258 _ = client.LaunchProcess(testutils.ProgramHelloworld) 259 defer client.DetachProcess() 260 261 pid := client.tracingThreadIDs[0] 262 proc, _ := os.FindProcess(pid) 263 _ = proc.Signal(unix.SIGTERM) 264 265 event, err := client.ContinueAndWait() 266 if err != nil { 267 t.Fatalf("failed to continue and wait: %v", err) 268 } 269 expectedEvent := Event{Type: EventTypeTerminated, Data: int(unix.SIGTERM)} 270 if event != expectedEvent { 271 t.Fatalf("unexpected event: %#v", event) 272 } 273 } 274 275 func TestContinueAndWait_Stopped(t *testing.T) { 276 client := newRawClient() 277 _ = client.LaunchProcess(testutils.ProgramHelloworld) 278 defer client.DetachProcess() 279 280 pid := client.tracingThreadIDs[0] 281 proc, _ := os.FindProcess(pid) 282 _ = proc.Signal(unix.SIGUSR1) 283 284 // non-SIGTRAP signal is handled internally. 285 _, err := client.ContinueAndWait() 286 if err != nil { 287 t.Fatalf("failed to continue and wait: %v", err) 288 } 289 } 290 291 func TestContinueAndWait_CoreDump(t *testing.T) { 292 client := newRawClient() 293 _ = client.LaunchProcess(testutils.ProgramHelloworld) 294 defer client.DetachProcess() 295 296 pid := client.tracingThreadIDs[0] 297 proc, _ := os.FindProcess(pid) 298 _ = proc.Signal(unix.SIGQUIT) 299 300 event, err := client.ContinueAndWait() 301 if err != nil { 302 t.Fatalf("failed to continue and wait: %v", err) 303 } 304 expectedEvent := Event{Type: EventTypeCoreDump} 305 if event != expectedEvent { 306 t.Fatalf("unexpected event: %#v", event) 307 } 308 } 309 310 func TestContinueAndWait_Continued(t *testing.T) { 311 client := newRawClient() 312 _ = client.LaunchProcess(testutils.ProgramHelloworld) 313 defer client.DetachProcess() 314 315 pid := client.tracingThreadIDs[0] 316 proc, _ := os.FindProcess(pid) 317 _ = proc.Signal(unix.SIGCONT) 318 319 _, err := client.ContinueAndWait() 320 if err != nil { 321 t.Fatalf("failed to continue and wait: %v", err) 322 } 323 } 324 325 func TestContinueAndWait_WaitAllChildrenExit(t *testing.T) { 326 client := newRawClient() 327 _ = client.LaunchProcess(testutils.ProgramHelloworld) 328 defer client.DetachProcess() 329 330 for { 331 event, err := client.ContinueAndWait() 332 if err != nil { 333 t.Fatalf("failed to continue and wait: %v", err) 334 } 335 336 if event.Type == EventTypeExited { 337 break 338 } 339 } 340 } 341 342 func TestStepAndWait(t *testing.T) { 343 client := newRawClient() 344 _ = client.LaunchProcess(testutils.ProgramInfloop) 345 defer client.DetachProcess() 346 347 pid := client.tracingThreadIDs[0] 348 event, err := client.StepAndWait(pid) 349 if err != nil { 350 t.Fatalf("failed to continue and wait: %v", err) 351 } 352 if event.Type != EventTypeTrapped { 353 t.Fatalf("unexpected event type: %v", event.Type) 354 } 355 stoppedPID := event.Data.([]int)[0] 356 if stoppedPID != pid { 357 t.Fatalf("unexpected process is stopped: %d", stoppedPID) 358 } 359 }