You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

157 lines
3.9 KiB

  1. // Copyright 2015 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. package main
  5. import (
  6. "bufio"
  7. "bytes"
  8. "fmt"
  9. "io"
  10. "log"
  11. "os"
  12. "regexp"
  13. "strconv"
  14. "strings"
  15. )
  16. var (
  17. hexDumpRE = regexp.MustCompile(`^\t(0x[0-9a-f]{4,})(( ([0-9a-f]{2}| )){16}) [ -\x7F]{1,16}\n`)
  18. listingRE = regexp.MustCompile(`^\t(0x[0-9a-f]{4,}) ([0-9]{4,}) \(.*:[0-9]+\)\t`)
  19. )
  20. // okdiffs lists regular expressions for lines to consider minor mismatches.
  21. // If one of these regexps matches both of a pair of unequal lines, the mismatch
  22. // is reported but not treated as the one worth looking for.
  23. // For example, differences in the TEXT line are typically frame size
  24. // changes due to optimization decisions made in the body of the function.
  25. // Better to keep looking for the actual difference.
  26. // Similarly, forward jumps might have different offsets due to a
  27. // change in instruction encoding later on.
  28. // Better to find that change.
  29. var okdiffs = []*regexp.Regexp{
  30. regexp.MustCompile(`\) TEXT[ ].*,\$`),
  31. regexp.MustCompile(`\) WORD[ ].*,\$`),
  32. regexp.MustCompile(`\) (B|BR|JMP) `),
  33. regexp.MustCompile(`\) FUNCDATA `),
  34. regexp.MustCompile(`\\(z|x00)`),
  35. regexp.MustCompile(`\$\([0-9]\.[0-9]+e[+\-][0-9]+\)`),
  36. regexp.MustCompile(`size=.*value=.*args=.*locals=`),
  37. }
  38. func compareLogs(outfile string) string {
  39. f1, err := os.Open(outfile + ".log")
  40. if err != nil {
  41. log.Fatal(err)
  42. }
  43. defer f1.Close()
  44. f2, err := os.Open(outfile + ".stash.log")
  45. if err != nil {
  46. log.Fatal(err)
  47. }
  48. defer f2.Close()
  49. b1 := bufio.NewReader(f1)
  50. b2 := bufio.NewReader(f2)
  51. offset := int64(0)
  52. textOffset := offset
  53. textLineno := 0
  54. lineno := 0
  55. var line1, line2 string
  56. var prefix bytes.Buffer
  57. Reading:
  58. for {
  59. var err1, err2 error
  60. line1, err1 = b1.ReadString('\n')
  61. line2, err2 = b2.ReadString('\n')
  62. if strings.Contains(line1, ")\tTEXT\t") {
  63. textOffset = offset
  64. textLineno = lineno
  65. }
  66. offset += int64(len(line1))
  67. lineno++
  68. if err1 == io.EOF && err2 == io.EOF {
  69. return "no differences in debugging output"
  70. }
  71. if lineno == 1 || line1 == line2 && err1 == nil && err2 == nil {
  72. continue
  73. }
  74. // Lines are inconsistent. Worth stopping?
  75. for _, re := range okdiffs {
  76. if re.MatchString(line1) && re.MatchString(line2) {
  77. fmt.Fprintf(&prefix, "inconsistent log line:\n%s:%d:\n\t%s\n%s:%d:\n\t%s\n\n",
  78. f1.Name(), lineno, strings.TrimSuffix(line1, "\n"),
  79. f2.Name(), lineno, strings.TrimSuffix(line2, "\n"))
  80. continue Reading
  81. }
  82. }
  83. if err1 != nil {
  84. line1 = err1.Error()
  85. }
  86. if err2 != nil {
  87. line2 = err2.Error()
  88. }
  89. break
  90. }
  91. msg := fmt.Sprintf("inconsistent log line:\n%s:%d:\n\t%s\n%s:%d:\n\t%s",
  92. f1.Name(), lineno, strings.TrimSuffix(line1, "\n"),
  93. f2.Name(), lineno, strings.TrimSuffix(line2, "\n"))
  94. if m := hexDumpRE.FindStringSubmatch(line1); m != nil {
  95. target, err := strconv.ParseUint(m[1], 0, 64)
  96. if err != nil {
  97. goto Skip
  98. }
  99. m2 := hexDumpRE.FindStringSubmatch(line2)
  100. if m2 == nil {
  101. goto Skip
  102. }
  103. fields1 := strings.Fields(m[2])
  104. fields2 := strings.Fields(m2[2])
  105. i := 0
  106. for i < len(fields1) && i < len(fields2) && fields1[i] == fields2[i] {
  107. i++
  108. }
  109. target += uint64(i)
  110. f1.Seek(textOffset, 0)
  111. b1 = bufio.NewReader(f1)
  112. last := ""
  113. lineno := textLineno
  114. limitAddr := uint64(0)
  115. lastAddr := uint64(0)
  116. for {
  117. line1, err1 := b1.ReadString('\n')
  118. if err1 != nil {
  119. break
  120. }
  121. lineno++
  122. if m := listingRE.FindStringSubmatch(line1); m != nil {
  123. addr, _ := strconv.ParseUint(m[1], 0, 64)
  124. if addr > target {
  125. limitAddr = addr
  126. break
  127. }
  128. last = line1
  129. lastAddr = addr
  130. } else if hexDumpRE.FindStringSubmatch(line1) != nil {
  131. break
  132. }
  133. }
  134. if last != "" {
  135. msg = fmt.Sprintf("assembly instruction at %#04x-%#04x:\n%s:%d\n\t%s\n\n%s",
  136. lastAddr, limitAddr, f1.Name(), lineno-1, strings.TrimSuffix(last, "\n"), msg)
  137. }
  138. }
  139. Skip:
  140. return prefix.String() + msg
  141. }