"time"
)
-var update = flag.Bool("u", false, "update debug_test reference files")
-var verbose = flag.Bool("v", false, "print more information about what's happening")
-var dryrun = flag.Bool("n", false, "just print the command line and first bits")
-var delve = flag.Bool("d", false, "use delve instead of gdb")
+var update = flag.Bool("u", false, "update test reference files")
+var verbose = flag.Bool("v", false, "print debugger interactions (very verbose)")
+var dryrun = flag.Bool("n", false, "just print the command line and first debugging bits")
+var delve = flag.Bool("d", false, "use Delve (dlv) instead of gdb, use dlv reverence files")
var force = flag.Bool("f", false, "force run under not linux-amd64; also do not use tempdir")
+var repeats = flag.Bool("r", false, "detect repeats in debug steps and don't ignore them")
+var inlines = flag.Bool("i", false, "do inlining for gdb (makes testing flaky till inlining info is correct)")
+
var hexRe = regexp.MustCompile("0x[a-zA-Z0-9]+")
var numRe = regexp.MustCompile("-?[0-9]+")
var stringRe = regexp.MustCompile("\"([^\\\"]|(\\.))*\"")
-var gdb = "gdb" // Might be "ggdb" on Darwin, because gdb no longer part of XCode
+var gdb = "gdb" // Might be "ggdb" on Darwin, because gdb no longer part of XCode
+var debugger = "gdb" // For naming files, etc.
// TestNexting go-builds a file, then uses a debugger (default gdb, optionally delve)
// to next through the generated executable, recording each line landed at, and
// Flag -v is ever-so-slightly verbose.
// Flag -n is for dry-run, and prints the shell and first debug commands.
//
+// Because this test (combined with existing compiler deficiencies) is flaky,
+// for gdb-based testing by default inlining is disabled
+// (otherwise output depends on library internals)
+// and for both gdb and dlv by default repeated lines in the next stream are ignored
+// (because this appears to be timing-dependent in gdb, and the cleanest fix is in code common to gdb and dlv).
+//
+// Also by default, any source code outside of .../testdata/ is not mentioned
+// in the debugging histories. This deals both with inlined library code once
+// the compiler is generating clean inline records, and also deals with
+// runtime code between return from main and process exit. This is hidden
+// so that those files (in the runtime/library) can change without affecting
+// this test.
+//
+// These choices can be reversed with -i (inlining on) and -r (repeats detected) which
+// will also cause their own failures against the expected outputs. Note that if the compiler
+// and debugger were behaving properly, the inlined code and repeated lines would not appear,
+// so the expected output is closer to what we hope to see, though it also encodes all our
+// current bugs.
+//
// The file being tested may contain comments of the form
// //DBG-TAG=(v1,v2,v3)
// where DBG = {gdb,dlv} and TAG={dbg,opt}
// go test debug_test.go -args -u -d
func TestNexting(t *testing.T) {
- // Skip this test in an ordinary run.bash. Too many things
- // can cause it to break.
+ skipReasons := "" // Many possible skip reasons, list all that apply
if testing.Short() {
- t.Skip("skipping in short mode; see issue #22206")
+ skipReasons = "not run in short mode; "
}
-
testenv.MustHaveGoBuild(t)
if !*delve && !*force && !(runtime.GOOS == "linux" && runtime.GOARCH == "amd64") {
// Various architectures tend to differ slightly sometimes, and keeping them
// all in sync is a pain for people who don't have them all at hand,
// so limit testing to amd64 (for now)
-
- t.Skip("Skipped unless -d (delve), -f (force), or linux-amd64")
+ skipReasons += "not run unless linux-amd64 or -d or -f; "
}
if *delve {
+ debugger = "dlv"
_, err := exec.LookPath("dlv")
if err != nil {
- t.Fatal("dlv specified on command line with -d but no dlv on path")
+ skipReasons += "not run because dlv (requested by -d option) not on path; "
}
} else {
_, err := exec.LookPath(gdb)
if err != nil {
if runtime.GOOS != "darwin" {
- t.Skip("Skipped because gdb not available")
- }
- _, err = exec.LookPath("ggdb")
- if err != nil {
- t.Skip("Skipped because gdb (and also ggdb) not available")
+ skipReasons += "not run because gdb not on path; "
+ } else {
+ _, err = exec.LookPath("ggdb")
+ if err != nil {
+ skipReasons += "not run because gdb (and also ggdb) not on path; "
+ } else {
+ gdb = "ggdb"
+ }
}
- gdb = "ggdb"
}
}
- t.Run("dbg", func(t *testing.T) {
+ if skipReasons != "" {
+ t.Skip(skipReasons[:len(skipReasons)-2])
+ }
+
+ t.Run("dbg-"+debugger, func(t *testing.T) {
testNexting(t, "hist", "dbg", "-N -l")
})
- t.Run("opt", func(t *testing.T) {
+ t.Run("opt-"+debugger, func(t *testing.T) {
// If this is test is run with a runtime compiled with -N -l, it is very likely to fail.
// This occurs in the noopt builders (for example).
if gogcflags := os.Getenv("GO_GCFLAGS"); *force || (!strings.Contains(gogcflags, "-N") && !strings.Contains(gogcflags, "-l")) {
- testNexting(t, "hist", "opt", "")
+ if *delve || *inlines {
+ testNexting(t, "hist", "opt", "")
+ } else {
+ // For gdb, disable inlining so that a compiler test does not depend on library code.
+ testNexting(t, "hist", "opt", "-l")
+ }
} else {
t.Skip("skipping for unoptimized runtime")
}
func testNexting(t *testing.T, base, tag, gcflags string) {
// (1) In testdata, build sample.go into sample
// (2) Run debugger gathering a history
- // (3) Read expected history from testdata/sample.nexts
- // optionally, write out testdata/sample.nexts
+ // (3) Read expected history from testdata/sample.<variant>.nexts
+ // optionally, write out testdata/sample.<variant>.nexts
exe := filepath.Join("testdata", base)
- logbase := exe + "-" + tag
- tmpbase := logbase + "-test"
+ logbase := exe + "." + tag
+ tmpbase := filepath.Join("testdata", "test-"+base+"."+tag)
if !*force {
tmpdir, err := ioutil.TempDir("", "debug_test")
runGo(t, "", "build", "-o", exe, "-gcflags", gcflags, filepath.Join("testdata", base+".go"))
}
var h1 *nextHist
- var nextlog, tmplog string
+
+ nextlog := logbase + "-" + debugger + ".nexts"
+ tmplog := tmpbase + "-" + debugger + ".nexts"
if *delve {
h1 = dlvTest(tag, exe, 1000)
- nextlog = logbase + ".delve-nexts"
- tmplog = tmpbase + ".delve-nexts"
} else {
h1 = gdbTest(tag, exe, 1000)
- nextlog = logbase + ".gdb-nexts"
- tmplog = tmpbase + ".gdb-nexts"
}
if *dryrun {
fmt.Printf("# Tag for above is %s\n", tag)
type dbgr interface {
start()
- do(s string)
stepnext(s string) bool // step or next, possible with parameter, gets line etc. returns true for success, false for unsure response
quit()
hist() *nextHist
}
+// gdbTest runs the debugger test with gdb and returns the history
func gdbTest(tag, executable string, maxNext int, args ...string) *nextHist {
dbg := newGdb(tag, executable, args...)
dbg.start()
return h
}
+// dlvTest runs the debugger test with dlv and returns the history
func dlvTest(tag, executable string, maxNext int, args ...string) *nextHist {
dbg := newDelve(tag, executable, args...)
dbg.start()
return stdout.String()
}
+// tstring provides two strings, o (stdout) and e (stderr)
type tstring struct {
o string
e string
type pos struct {
line uint16
- file uint8
+ file uint8 // Artifact of plans to implement differencing instead of calling out to diff.
}
type nextHist struct {
f2i map[string]uint8
fs []string
- ps []pos // TODO: plan to automatically do the minimum distance conversion between a reference and a run for nicer errors.
+ ps []pos
texts []string
vars [][]string
}
}
}
-func (h *nextHist) add(file, line, text string) {
+func (h *nextHist) add(file, line, text string) bool {
+ // Only record source code in testdata unless the inlines flag is set
+ if !*inlines && !strings.Contains(file, "/testdata/") {
+ return false
+ }
fi := h.f2i[file]
if fi == 0 {
h.fs = append(h.fs, file)
panic(fmt.Sprintf("Non-numeric line: %s, error %v\n", line, err))
}
}
- h.ps = append(h.ps, pos{line: uint16(li), file: fi})
- h.texts = append(h.texts, text)
- h.vars = append(h.vars, []string{})
+ l := len(h.ps)
+ p := pos{line: uint16(li), file: fi}
+
+ if l == 0 || *repeats || h.ps[l-1] != p {
+ h.ps = append(h.ps, p)
+ h.texts = append(h.texts, text)
+ h.vars = append(h.vars, []string{})
+ return true
+ }
+ return false
}
func (h *nextHist) addVar(text string) {
return true
}
+// canonFileName strips everything before "src/" from a filename.
+// This makes file names portable across different machines,
+// home directories, and temporary directories.
func canonFileName(f string) string {
i := strings.Index(f, "/src/")
if i != -1 {
s.file = fn
s.function = locations[1]
s.ioState.history.add(s.file, s.line, excerpt)
+ // TODO: here is where variable processing will be added. See gdbState.stepnext as a guide.
+ // Adding this may require some amount of normalization so that logs are comparable.
return true
}
- fmt.Printf("DID NOT MATCH EXPECTED NEXT OUTPUT\nO='%s'\nE='%s'\n", x.o, x.e)
+ if *verbose {
+ fmt.Printf("DID NOT MATCH EXPECTED NEXT OUTPUT\nO='%s'\nE='%s'\n", x.o, x.e)
+ }
return false
}
panic(fmt.Sprintf("There was an error [start] running '%s', %v\n", line, err))
}
s.ioState.readExpecting(-1, 5000, "Type 'help' for list of commands.")
- expect("Breakpoint [0-9]+ set at ", s.ioState.writeRead("b main.main\n"))
+ expect("Breakpoint [0-9]+ set at ", s.ioState.writeReadExpect("b main.main\n", "[(]dlv[)] "))
s.stepnext("c")
}
func (s *delveState) quit() {
- s.do("q")
-}
-
-func (s *delveState) do(ss string) {
- expect("", s.ioState.writeRead(ss+"\n"))
+ expect("", s.ioState.writeRead("q\n"))
}
/* Gdb */
}
if *dryrun {
fmt.Printf("%s\n", asCommandLine("", s.cmd))
- fmt.Printf("b main.main\n")
+ fmt.Printf("tbreak main.main\n")
fmt.Printf("%s\n", run)
return
}
line := asCommandLine("", s.cmd)
panic(fmt.Sprintf("There was an error [start] running '%s', %v\n", line, err))
}
- s.ioState.readExpecting(-1, 5000, "[(]gdb[)] ")
+ s.ioState.readExpecting(-1, -1, "[(]gdb[)] ")
x := s.ioState.writeReadExpect("b main.main\n", "[(]gdb[)] ")
expect("Breakpoint [0-9]+ at", x)
s.stepnext(run)
excerpts := s.atLineRe.FindStringSubmatch(x.o)
locations := s.funcFileLinePCre.FindStringSubmatch(x.o)
excerpt := ""
+ addedLine := false
if len(excerpts) == 0 && len(locations) == 0 {
- fmt.Printf("DID NOT MATCH %s", x.o)
+ if *verbose {
+ fmt.Printf("DID NOT MATCH %s", x.o)
+ }
return false
}
if len(excerpts) > 0 {
s.line = locations[3]
s.file = fn
s.function = locations[1]
- s.ioState.history.add(s.file, s.line, excerpt)
+ addedLine = s.ioState.history.add(s.file, s.line, excerpt)
}
if len(excerpts) > 0 {
if *verbose {
fmt.Printf(" %s\n", excerpts[2])
}
s.line = excerpts[2]
- s.ioState.history.add(s.file, s.line, excerpt)
+ addedLine = s.ioState.history.add(s.file, s.line, excerpt)
}
+ if !addedLine {
+ // True if this was a repeat line
+ return true
+ }
// Look for //gdb-<tag>=(v1,v2,v3) and print v1, v2, v3
vars := varsToPrint(excerpt, "//gdb-"+s.tag+"=(")
for _, v := range vars {
substitutions = v[slashIndex:]
v = v[:slashIndex]
}
- response := s.ioState.writeRead("p " + v + "\n").String()
+ response := s.ioState.writeReadExpect("p "+v+"\n", "[(]gdb[)] ").String()
// expect something like "$1 = ..."
dollar := strings.Index(response, "$")
cr := strings.Index(response, "\n")
return true
}
+// varsToPrint takes a source code line, and extracts the comma-separated variable names
+// found between lookfor and the next ")".
+// For example, if line includes "... //gdb-foo=(v1,v2,v3)" and
+// lookfor="//gdb-foo=(", then varsToPrint returns ["v1", "v2", "v3"]
func varsToPrint(line, lookfor string) []string {
var vars []string
if strings.Contains(line, lookfor) {
}
}
-func (s *gdbState) do(ss string) {
- expect("", s.ioState.writeRead(ss+"\n"))
-}
-
type ioState struct {
stdout io.ReadCloser
stderr io.ReadCloser
return s.history
}
-const (
- interlineDelay = 300
-)
-
+// writeRead writes ss, then reads stdout and stderr, waiting 500ms to
+// be sure all the output has appeared.
func (s *ioState) writeRead(ss string) tstring {
if *verbose {
fmt.Printf("=> %s", ss)
if err != nil {
panic(fmt.Sprintf("There was an error writing '%s', %v\n", ss, err))
}
- return s.readWithDelay(-1, interlineDelay)
+ return s.readExpecting(-1, 500, "")
}
-func (s *ioState) writeReadExpect(ss, expect string) tstring {
+// writeReadExpect writes ss, then reads stdout and stderr until something
+// that matches expectRE appears. expectRE should not be ""
+func (s *ioState) writeReadExpect(ss, expectRE string) tstring {
if *verbose {
fmt.Printf("=> %s", ss)
}
+ if expectRE == "" {
+ panic("expectRE should not be empty; use .* instead")
+ }
_, err := io.WriteString(s.stdin, ss)
if err != nil {
panic(fmt.Sprintf("There was an error writing '%s', %v\n", ss, err))
}
- return s.readExpecting(-1, interlineDelay, expect)
-}
-
-func (s *ioState) readWithDelay(millis, interlineTimeout int) tstring {
- return s.readExpecting(millis, interlineTimeout, "")
+ return s.readExpecting(-1, -1, expectRE)
}
-func (s *ioState) readExpecting(millis, interlineTimeout int, expected string) tstring {
+func (s *ioState) readExpecting(millis, interlineTimeout int, expectedRE string) tstring {
timeout := time.Millisecond * time.Duration(millis)
interline := time.Millisecond * time.Duration(interlineTimeout)
s.last = tstring{}
var re *regexp.Regexp
- if expected != "" {
- re = regexp.MustCompile(expected)
+ if expectedRE != "" {
+ re = regexp.MustCompile(expectedRE)
}
loop:
for {
36: hist := make([]int, 10)
37: var reader io.Reader = strings.NewReader(cannedInput) //gdb-dbg=(hist/A,cannedInput/A)
13: "strings"
- src/strings/reader.go
-150: func NewReader(s string) *Reader { return &Reader{s, 0, -1} }
- ./testdata/hist.go
38: if len(os.Args) > 1 {
8: "bufio"
- src/bufio/scan.go
-84: split: ScanLines,
-74: MaxScanTokenSize = 64 * 1024
- ./testdata/hist.go
47: for scanner.Scan() {
-47: for scanner.Scan() {
- src/bufio/scan.go
-107: return string(s.token)
- ./testdata/hist.go
49: i, err := strconv.ParseInt(s, 10, 64)
50: if err != nil { //gdb-dbg=(i)
54: hist = ensure(int(i), hist)
55: hist[int(i)]++
-55: hist[int(i)]++
47: for scanner.Scan() {
- src/bufio/scan.go
-107: return string(s.token)
- ./testdata/hist.go
49: i, err := strconv.ParseInt(s, 10, 64)
50: if err != nil { //gdb-dbg=(i)
54: hist = ensure(int(i), hist)
55: hist[int(i)]++
-55: hist[int(i)]++
47: for scanner.Scan() {
- src/bufio/scan.go
-107: return string(s.token)
- ./testdata/hist.go
49: i, err := strconv.ParseInt(s, 10, 64)
50: if err != nil { //gdb-dbg=(i)
54: hist = ensure(int(i), hist)
55: hist[int(i)]++
-55: hist[int(i)]++
47: for scanner.Scan() {
- src/bufio/scan.go
-107: return string(s.token)
- ./testdata/hist.go
49: i, err := strconv.ParseInt(s, 10, 64)
50: if err != nil { //gdb-dbg=(i)
54: hist = ensure(int(i), hist)
55: hist[int(i)]++
-55: hist[int(i)]++
47: for scanner.Scan() {
- src/bufio/scan.go
-107: return string(s.token)
- ./testdata/hist.go
49: i, err := strconv.ParseInt(s, 10, 64)
50: if err != nil { //gdb-dbg=(i)
54: hist = ensure(int(i), hist)
55: hist[int(i)]++
-55: hist[int(i)]++
47: for scanner.Scan() {
- src/bufio/scan.go
-107: return string(s.token)
- ./testdata/hist.go
49: i, err := strconv.ParseInt(s, 10, 64)
50: if err != nil { //gdb-dbg=(i)
54: hist = ensure(int(i), hist)
55: hist[int(i)]++
-55: hist[int(i)]++
47: for scanner.Scan() {
- src/bufio/scan.go
-107: return string(s.token)
- ./testdata/hist.go
49: i, err := strconv.ParseInt(s, 10, 64)
50: if err != nil { //gdb-dbg=(i)
54: hist = ensure(int(i), hist)
55: hist[int(i)]++
-55: hist[int(i)]++
47: for scanner.Scan() {
- src/bufio/scan.go
-107: return string(s.token)
- ./testdata/hist.go
49: i, err := strconv.ParseInt(s, 10, 64)
50: if err != nil { //gdb-dbg=(i)
54: hist = ensure(int(i), hist)
55: hist[int(i)]++
-55: hist[int(i)]++
47: for scanner.Scan() {
- src/bufio/scan.go
-107: return string(s.token)
- ./testdata/hist.go
49: i, err := strconv.ParseInt(s, 10, 64)
50: if err != nil { //gdb-dbg=(i)
54: hist = ensure(int(i), hist)
55: hist[int(i)]++
-55: hist[int(i)]++
47: for scanner.Scan() {
- src/bufio/scan.go
-107: return string(s.token)
- ./testdata/hist.go
49: i, err := strconv.ParseInt(s, 10, 64)
50: if err != nil { //gdb-dbg=(i)
54: hist = ensure(int(i), hist)
55: hist[int(i)]++
-55: hist[int(i)]++
47: for scanner.Scan() {
59: for i, a := range hist {
60: if a == 0 {
-60: if a == 0 {
65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
64: n += a
65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
59: for i, a := range hist {
65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
60: if a == 0 {
-60: if a == 0 {
65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
64: n += a
65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
59: for i, a := range hist {
65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
60: if a == 0 {
-60: if a == 0 {
-60: if a == 0 {
-60: if a == 0 {
65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
64: n += a
65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
60: if a == 0 {
68: }
- src/runtime/proc.go
-201: if atomic.Load(&runningPanicDefers) != 0 {
-210: if atomic.Load(&panicking) != 0 {
-214: exit(0)
src/cmd/compile/internal/ssa/testdata/hist.go
35: func main() {
-35: func main() {
36: hist := make([]int, 10)
37: var reader io.Reader = strings.NewReader(cannedInput) //gdb-dbg=(hist/A,cannedInput/A)
-13: "strings"
-150: func NewReader(s string) *Reader { return &Reader{s, 0, -1} }
38: if len(os.Args) > 1 {
-8: "bufio"
-84: split: ScanLines,
-74: MaxScanTokenSize = 64 * 1024
+46: scanner := bufio.NewScanner(reader)
47: for scanner.Scan() {
-107: return string(s.token)
+48: s := scanner.Text()
49: i, err := strconv.ParseInt(s, 10, 64)
50: if err != nil { //gdb-dbg=(i)
54: hist = ensure(int(i), hist)
55: hist[int(i)]++
47: for scanner.Scan() {
-107: return string(s.token)
+48: s := scanner.Text()
49: i, err := strconv.ParseInt(s, 10, 64)
50: if err != nil { //gdb-dbg=(i)
54: hist = ensure(int(i), hist)
55: hist[int(i)]++
47: for scanner.Scan() {
-107: return string(s.token)
+48: s := scanner.Text()
49: i, err := strconv.ParseInt(s, 10, 64)
50: if err != nil { //gdb-dbg=(i)
54: hist = ensure(int(i), hist)
55: hist[int(i)]++
47: for scanner.Scan() {
-107: return string(s.token)
+48: s := scanner.Text()
49: i, err := strconv.ParseInt(s, 10, 64)
50: if err != nil { //gdb-dbg=(i)
54: hist = ensure(int(i), hist)
55: hist[int(i)]++
47: for scanner.Scan() {
-107: return string(s.token)
+48: s := scanner.Text()
49: i, err := strconv.ParseInt(s, 10, 64)
50: if err != nil { //gdb-dbg=(i)
54: hist = ensure(int(i), hist)
55: hist[int(i)]++
47: for scanner.Scan() {
-107: return string(s.token)
+48: s := scanner.Text()
49: i, err := strconv.ParseInt(s, 10, 64)
50: if err != nil { //gdb-dbg=(i)
54: hist = ensure(int(i), hist)
55: hist[int(i)]++
47: for scanner.Scan() {
-107: return string(s.token)
+48: s := scanner.Text()
49: i, err := strconv.ParseInt(s, 10, 64)
50: if err != nil { //gdb-dbg=(i)
54: hist = ensure(int(i), hist)
55: hist[int(i)]++
47: for scanner.Scan() {
-107: return string(s.token)
+48: s := scanner.Text()
49: i, err := strconv.ParseInt(s, 10, 64)
50: if err != nil { //gdb-dbg=(i)
54: hist = ensure(int(i), hist)
55: hist[int(i)]++
47: for scanner.Scan() {
-107: return string(s.token)
+48: s := scanner.Text()
49: i, err := strconv.ParseInt(s, 10, 64)
50: if err != nil { //gdb-dbg=(i)
54: hist = ensure(int(i), hist)
55: hist[int(i)]++
47: for scanner.Scan() {
-107: return string(s.token)
+48: s := scanner.Text()
49: i, err := strconv.ParseInt(s, 10, 64)
50: if err != nil { //gdb-dbg=(i)
54: hist = ensure(int(i), hist)
47: for scanner.Scan() {
59: for i, a := range hist {
60: if a == 0 {
-60: if a == 0 {
65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
64: n += a
65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
59: for i, a := range hist {
65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
60: if a == 0 {
-60: if a == 0 {
65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
64: n += a
65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
59: for i, a := range hist {
65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
60: if a == 0 {
-60: if a == 0 {
-60: if a == 0 {
-60: if a == 0 {
65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
64: n += a
65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
65: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
60: if a == 0 {
68: }
- src/runtime/proc.go
-201: if atomic.Load(&runningPanicDefers) != 0 {
-201: if atomic.Load(&runningPanicDefers) != 0 {
-210: if atomic.Load(&panicking) != 0 {
-214: exit(0)