Source file src/runtime/runtime-lldb_test.go

     1  // Copyright 2016 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package runtime_test
     6  
     7  import (
     8  	"internal/testenv"
     9  	"os"
    10  	"os/exec"
    11  	"path/filepath"
    12  	"runtime"
    13  	"strings"
    14  	"testing"
    15  )
    16  
    17  var lldbPath string
    18  
    19  func checkLldbPython(t *testing.T) {
    20  	cmd := exec.Command("lldb", "-P")
    21  	out, err := cmd.CombinedOutput()
    22  	if err != nil {
    23  		t.Skipf("skipping due to issue running lldb: %v\n%s", err, out)
    24  	}
    25  	lldbPath = strings.TrimSpace(string(out))
    26  
    27  	cmd = exec.Command("/usr/bin/python2.7", "-c", "import sys;sys.path.append(sys.argv[1]);import lldb; print('go lldb python support')", lldbPath)
    28  	out, err = cmd.CombinedOutput()
    29  
    30  	if err != nil {
    31  		t.Skipf("skipping due to issue running python: %v\n%s", err, out)
    32  	}
    33  	if string(out) != "go lldb python support\n" {
    34  		t.Skipf("skipping due to lack of python lldb support: %s", out)
    35  	}
    36  
    37  	if runtime.GOOS == "darwin" {
    38  		// Try to see if we have debugging permissions.
    39  		cmd = exec.Command("/usr/sbin/DevToolsSecurity", "-status")
    40  		out, err = cmd.CombinedOutput()
    41  		if err != nil {
    42  			t.Skipf("DevToolsSecurity failed: %v", err)
    43  		} else if !strings.Contains(string(out), "enabled") {
    44  			t.Skip(string(out))
    45  		}
    46  		cmd = exec.Command("/usr/bin/groups")
    47  		out, err = cmd.CombinedOutput()
    48  		if err != nil {
    49  			t.Skipf("groups failed: %v", err)
    50  		} else if !strings.Contains(string(out), "_developer") {
    51  			t.Skip("Not in _developer group")
    52  		}
    53  	}
    54  }
    55  
    56  const lldbHelloSource = `
    57  package main
    58  import "fmt"
    59  func main() {
    60  	mapvar := make(map[string]string,5)
    61  	mapvar["abc"] = "def"
    62  	mapvar["ghi"] = "jkl"
    63  	intvar := 42
    64  	ptrvar := &intvar
    65  	fmt.Println("hi") // line 10
    66  	_ = ptrvar
    67  }
    68  `
    69  
    70  const lldbScriptSource = `
    71  import sys
    72  sys.path.append(sys.argv[1])
    73  import lldb
    74  import os
    75  
    76  TIMEOUT_SECS = 5
    77  
    78  debugger = lldb.SBDebugger.Create()
    79  debugger.SetAsync(True)
    80  target = debugger.CreateTargetWithFileAndArch("a.exe", None)
    81  if target:
    82    print "Created target"
    83    main_bp = target.BreakpointCreateByLocation("main.go", 10)
    84    if main_bp:
    85      print "Created breakpoint"
    86    process = target.LaunchSimple(None, None, os.getcwd())
    87    if process:
    88      print "Process launched"
    89      listener = debugger.GetListener()
    90      process.broadcaster.AddListener(listener, lldb.SBProcess.eBroadcastBitStateChanged)
    91      while True:
    92        event = lldb.SBEvent()
    93        if listener.WaitForEvent(TIMEOUT_SECS, event):
    94          if lldb.SBProcess.GetRestartedFromEvent(event):
    95            continue
    96          state = process.GetState()
    97          if state in [lldb.eStateUnloaded, lldb.eStateLaunching, lldb.eStateRunning]:
    98            continue
    99        else:
   100          print "Timeout launching"
   101        break
   102      if state == lldb.eStateStopped:
   103        for t in process.threads:
   104          if t.GetStopReason() == lldb.eStopReasonBreakpoint:
   105            print "Hit breakpoint"
   106            frame = t.GetFrameAtIndex(0)
   107            if frame:
   108              if frame.line_entry:
   109                print "Stopped at %s:%d" % (frame.line_entry.file.basename, frame.line_entry.line)
   110              if frame.function:
   111                print "Stopped in %s" % (frame.function.name,)
   112              var = frame.FindVariable('intvar')
   113              if var:
   114                print "intvar = %s" % (var.GetValue(),)
   115              else:
   116                print "no intvar"
   117      else:
   118        print "Process state", state
   119      process.Destroy()
   120  else:
   121    print "Failed to create target a.exe"
   122  
   123  lldb.SBDebugger.Destroy(debugger)
   124  sys.exit()
   125  `
   126  
   127  const expectedLldbOutput = `Created target
   128  Created breakpoint
   129  Process launched
   130  Hit breakpoint
   131  Stopped at main.go:10
   132  Stopped in main.main
   133  intvar = 42
   134  `
   135  
   136  func TestLldbPython(t *testing.T) {
   137  	testenv.MustHaveGoBuild(t)
   138  	testenv.SkipFlaky(t, 31188)
   139  
   140  	checkLldbPython(t)
   141  
   142  	dir := t.TempDir()
   143  
   144  	src := filepath.Join(dir, "main.go")
   145  	err := os.WriteFile(src, []byte(lldbHelloSource), 0644)
   146  	if err != nil {
   147  		t.Fatalf("failed to create src file: %v", err)
   148  	}
   149  
   150  	mod := filepath.Join(dir, "go.mod")
   151  	err = os.WriteFile(mod, []byte("module lldbtest"), 0644)
   152  	if err != nil {
   153  		t.Fatalf("failed to create mod file: %v", err)
   154  	}
   155  
   156  	// As of 2018-07-17, lldb doesn't support compressed DWARF, so
   157  	// disable it for this test.
   158  	cmd := exec.Command(testenv.GoToolPath(t), "build", "-gcflags=all=-N -l", "-ldflags=-compressdwarf=false", "-o", "a.exe")
   159  	cmd.Dir = dir
   160  	cmd.Env = append(os.Environ(), "GOPATH=") // issue 31100
   161  	out, err := cmd.CombinedOutput()
   162  	if err != nil {
   163  		t.Fatalf("building source %v\n%s", err, out)
   164  	}
   165  
   166  	src = filepath.Join(dir, "script.py")
   167  	err = os.WriteFile(src, []byte(lldbScriptSource), 0755)
   168  	if err != nil {
   169  		t.Fatalf("failed to create script: %v", err)
   170  	}
   171  
   172  	cmd = exec.Command("/usr/bin/python2.7", "script.py", lldbPath)
   173  	cmd.Dir = dir
   174  	got, _ := cmd.CombinedOutput()
   175  
   176  	if string(got) != expectedLldbOutput {
   177  		if strings.Contains(string(got), "Timeout launching") {
   178  			t.Skip("Timeout launching")
   179  		}
   180  		t.Fatalf("Unexpected lldb output:\n%s", got)
   181  	}
   182  }
   183  

View as plain text