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  }