Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201105173854-bc9fc8d8c4bc / cmd / toolstash / cmp.go
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 }