]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/link: fix padding for dwarf aranges on 32 bit platforms.
authorRyan Brown <ribrdb@google.com>
Thu, 11 Feb 2016 00:51:23 +0000 (16:51 -0800)
committerRuss Cox <rsc@golang.org>
Fri, 12 Feb 2016 19:13:11 +0000 (19:13 +0000)
Fixes #14278

Change-Id: I6a0c1370d595f0573ff0eb933450b1eea41f4bb3
Reviewed-on: https://go-review.googlesource.com/19452
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
src/cmd/link/internal/ld/dwarf.go
src/runtime/runtime-lldb_test.go [new file with mode: 0644]

index 563600d9a2a7c908fc21fb0297c7ea92a2fcaff5..a96b37a4bef32a4558b9543f5f1e314e53445b8c 100644 (file)
@@ -1946,7 +1946,9 @@ func writepub(ispub func(*DWDie) bool) int64 {
  */
 func writearanges() int64 {
        sectionstart := Cpos()
-       headersize := int(Rnd(4+2+4+1+1, int64(Thearch.Ptrsize))) // don't count unit_length field itself
+       // The first tuple is aligned to a multiple of the size of a single tuple
+       // (twice the size of an address)
+       headersize := int(Rnd(4+2+4+1+1, int64(Thearch.Ptrsize*2))) // don't count unit_length field itself
 
        for compunit := dwroot.child; compunit != nil; compunit = compunit.link {
                b := getattr(compunit, DW_AT_low_pc)
diff --git a/src/runtime/runtime-lldb_test.go b/src/runtime/runtime-lldb_test.go
new file mode 100644 (file)
index 0000000..2bd91c1
--- /dev/null
@@ -0,0 +1,262 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime_test
+
+import (
+       "debug/elf"
+       "debug/macho"
+       "encoding/binary"
+       "internal/testenv"
+       "io"
+       "io/ioutil"
+       "os"
+       "os/exec"
+       "path/filepath"
+       "runtime"
+       "strings"
+       "testing"
+)
+
+var lldbPath string
+
+func checkLldbPython(t *testing.T) {
+       cmd := exec.Command("lldb", "-P")
+       out, err := cmd.CombinedOutput()
+       if err != nil {
+               t.Skipf("skipping due to issue running lldb: %v\n%s", err, out)
+       }
+       lldbPath = strings.TrimSpace(string(out))
+
+       cmd = exec.Command("/usr/bin/python2.7", "-c", "import sys;sys.path.append(sys.argv[1]);import lldb; print('go lldb python support')", lldbPath)
+       out, err = cmd.CombinedOutput()
+
+       if err != nil {
+               t.Skipf("skipping due to issue running python: %v\n%s", err, out)
+       }
+       if string(out) != "go lldb python support\n" {
+               t.Skipf("skipping due to lack of python lldb support: %s", out)
+       }
+
+       if runtime.GOOS == "darwin" {
+               // Try to see if we have debugging permissions.
+               cmd = exec.Command("/usr/sbin/DevToolsSecurity", "-status")
+               out, err = cmd.CombinedOutput()
+               if err != nil {
+                       t.Skipf("DevToolsSecurity failed: %v", err)
+               } else if !strings.Contains(string(out), "enabled") {
+                       t.Skip(string(out))
+               }
+               cmd = exec.Command("/usr/bin/groups")
+               out, err = cmd.CombinedOutput()
+               if err != nil {
+                       t.Skipf("groups failed: %v", err)
+               } else if !strings.Contains(string(out), "_developer") {
+                       t.Skip("Not in _developer group")
+               }
+       }
+}
+
+const lldbHelloSource = `
+package main
+import "fmt"
+func main() {
+       mapvar := make(map[string]string,5)
+       mapvar["abc"] = "def"
+       mapvar["ghi"] = "jkl"
+       intvar := 42
+       ptrvar := &intvar
+       fmt.Println("hi") // line 10
+       _ = ptrvar
+}
+`
+
+const lldbScriptSource = `
+import sys
+sys.path.append(sys.argv[1])
+import lldb
+import os
+
+TIMEOUT_SECS = 5
+
+debugger = lldb.SBDebugger.Create()
+debugger.SetAsync(True)
+target = debugger.CreateTargetWithFileAndArch("a.exe", None)
+if target:
+  print "Created target"
+  main_bp = target.BreakpointCreateByLocation("main.go", 10)
+  if main_bp:
+    print "Created breakpoint"
+  process = target.LaunchSimple(None, None, os.getcwd())
+  if process:
+    print "Process launched"
+    listener = debugger.GetListener()
+    process.broadcaster.AddListener(listener, lldb.SBProcess.eBroadcastBitStateChanged)
+    while True:
+      event = lldb.SBEvent()
+      if listener.WaitForEvent(TIMEOUT_SECS, event):
+        if lldb.SBProcess.GetRestartedFromEvent(event):
+          continue
+        state = process.GetState()
+        if state in [lldb.eStateUnloaded, lldb.eStateLaunching, lldb.eStateRunning]:
+          continue
+      else:
+        print "Timeout launching"
+      break
+    if state == lldb.eStateStopped:
+      for t in process.threads:
+        if t.GetStopReason() == lldb.eStopReasonBreakpoint:
+          print "Hit breakpoint"
+          frame = t.GetFrameAtIndex(0)
+          if frame:
+            if frame.line_entry:
+              print "Stopped at %s:%d" % (frame.line_entry.file.basename, frame.line_entry.line)
+            if frame.function:
+              print "Stopped in %s" % (frame.function.name,)
+            var = frame.FindVariable('intvar')
+            if var:
+              print "intvar = %s" % (var.GetValue(),)
+            else:
+              print "no intvar"
+    else:
+      print "Process state", state
+    process.Destroy()
+else:
+  print "Failed to create target a.exe"
+
+lldb.SBDebugger.Destroy(debugger)
+sys.exit()
+`
+
+const expectedLldbOutput = `Created target
+Created breakpoint
+Process launched
+Hit breakpoint
+Stopped at main.go:10
+Stopped in main.main
+intvar = 42
+`
+
+func TestLldbPython(t *testing.T) {
+       testenv.MustHaveGoBuild(t)
+       if final := os.Getenv("GOROOT_FINAL"); final != "" && runtime.GOROOT() != final {
+               t.Skip("gdb test can fail with GOROOT_FINAL pending")
+       }
+
+       checkLldbPython(t)
+
+       dir, err := ioutil.TempDir("", "go-build")
+       if err != nil {
+               t.Fatalf("failed to create temp directory: %v", err)
+       }
+       defer os.RemoveAll(dir)
+
+       src := filepath.Join(dir, "main.go")
+       err = ioutil.WriteFile(src, []byte(lldbHelloSource), 0644)
+       if err != nil {
+               t.Fatalf("failed to create file: %v", err)
+       }
+
+       cmd := exec.Command("go", "build", "-gcflags", "-N -l", "-o", "a.exe")
+       cmd.Dir = dir
+       out, err := cmd.CombinedOutput()
+       if err != nil {
+               t.Fatalf("building source %v\n%s", err, out)
+       }
+
+       src = filepath.Join(dir, "script.py")
+       err = ioutil.WriteFile(src, []byte(lldbScriptSource), 0755)
+       if err != nil {
+               t.Fatalf("failed to create script: %v", err)
+       }
+
+       cmd = exec.Command("/usr/bin/python2.7", "script.py", lldbPath)
+       cmd.Dir = dir
+       got, _ := cmd.CombinedOutput()
+
+       if string(got) != expectedLldbOutput {
+               if strings.Contains(string(got), "Timeout launching") {
+                       t.Skip("Timeout launching")
+               }
+               t.Fatalf("Unexpected lldb output:\n%s", got)
+       }
+}
+
+// Check that aranges are valid even when lldb isn't installed.
+func TestDwarfAranges(t *testing.T) {
+       testenv.MustHaveGoBuild(t)
+       dir, err := ioutil.TempDir("", "go-build")
+       if err != nil {
+               t.Fatalf("failed to create temp directory: %v", err)
+       }
+       defer os.RemoveAll(dir)
+
+       src := filepath.Join(dir, "main.go")
+       err = ioutil.WriteFile(src, []byte(lldbHelloSource), 0644)
+       if err != nil {
+               t.Fatalf("failed to create file: %v", err)
+       }
+
+       cmd := exec.Command("go", "build", "-o", "a.exe")
+       cmd.Dir = dir
+       out, err := cmd.CombinedOutput()
+       if err != nil {
+               t.Fatalf("building source %v\n%s", err, out)
+       }
+
+       filename := filepath.Join(dir, "a.exe")
+       if f, err := elf.Open(filename); err == nil {
+               sect := f.Section(".debug_aranges")
+               if sect == nil {
+                       t.Fatal("Missing aranges section")
+               }
+               verifyAranges(t, f.ByteOrder, sect.Open())
+       } else if f, err := macho.Open(filename); err == nil {
+               sect := f.Section("__debug_aranges")
+               if sect == nil {
+                       t.Fatal("Missing aranges section")
+               }
+               verifyAranges(t, f.ByteOrder, sect.Open())
+       } else {
+               t.Skip("Not an elf or macho binary.")
+       }
+}
+
+func verifyAranges(t *testing.T, byteorder binary.ByteOrder, data io.ReadSeeker) {
+       var header struct {
+               UnitLength  uint32 // does not include the UnitLength field
+               Version     uint16
+               Offset      uint32
+               AddressSize uint8
+               SegmentSize uint8
+       }
+       for {
+               offset, err := data.Seek(0, 1)
+               if err != nil {
+                       t.Fatalf("Seek error: %v", err)
+               }
+               if err = binary.Read(data, byteorder, &header); err == io.EOF {
+                       return
+               } else if err != nil {
+                       t.Fatalf("Error reading arange header: %v", err)
+               }
+               tupleSize := int64(header.SegmentSize) + 2*int64(header.AddressSize)
+               lastTupleOffset := offset + int64(header.UnitLength) + 4 - tupleSize
+               if lastTupleOffset%tupleSize != 0 {
+                       t.Fatalf("Invalid arange length %d, (addr %d, seg %d)", header.UnitLength, header.AddressSize, header.SegmentSize)
+               }
+               if _, err = data.Seek(lastTupleOffset, 0); err != nil {
+                       t.Fatalf("Seek error: %v", err)
+               }
+               buf := make([]byte, tupleSize)
+               if n, err := data.Read(buf); err != nil || int64(n) < tupleSize {
+                       t.Fatalf("Read error: %v", err)
+               }
+               for _, val := range buf {
+                       if val != 0 {
+                               t.Fatalf("Invalid terminator")
+                       }
+               }
+       }
+}