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