github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/pkg/symbolizer/symbolizer_test.go (about) 1 // Copyright 2016 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 package symbolizer 5 6 import ( 7 "bufio" 8 "fmt" 9 "os" 10 "reflect" 11 "strconv" 12 "testing" 13 ) 14 15 func TestParse(t *testing.T) { 16 addresses := []struct { 17 pc uint64 18 resp string 19 frames []Frame 20 }{ 21 { 22 0xffffffff8180a42e, 23 "0xffffffff8180a42e\n" + 24 "__asan_report_load2_noabort\n" + 25 "mm/kasan/report.c:320\n", 26 []Frame{ 27 { 28 PC: 0xffffffff8180a42e, 29 Func: "__asan_report_load2_noabort", 30 File: "mm/kasan/report.c", 31 Line: 320, 32 Inline: false, 33 }, 34 }, 35 }, 36 { 37 0xffffffff8180a42d, 38 "0xffffffff8180a42d\n" + 39 "kasan_report\n" + 40 "mm/kasan/report.c:301\n" + 41 "__asan_report_load2_noabort\n" + 42 "mm/kasan/report.c:320\n", 43 []Frame{ 44 { 45 PC: 0xffffffff8180a42d, 46 Func: "kasan_report", 47 File: "mm/kasan/report.c", 48 Line: 301, 49 Inline: true, 50 }, 51 { 52 PC: 0xffffffff8180a42d, 53 Func: "__asan_report_load2_noabort", 54 File: "mm/kasan/report.c", 55 Line: 320, 56 Inline: false, 57 }, 58 }, 59 }, 60 { 61 0xffffffff82fdbe0b, 62 "0xffffffff82fdbe0b\n" + 63 "fbcon_invert_region\n" + 64 "drivers/video/console/fbcon.c:2750\n", 65 []Frame{ 66 { 67 PC: 0xffffffff82fdbe0b, 68 Func: "fbcon_invert_region", 69 File: "drivers/video/console/fbcon.c", 70 Line: 2750, 71 Inline: false, 72 }, 73 }, 74 }, 75 { 76 0x123124, 77 "0x0000000000123124\n" + 78 "??\n" + 79 "??:0\n", 80 nil, 81 }, 82 { 83 0xffffffffffffffff, 84 "0xffffffffffffffff\n" + 85 "??\n" + 86 "??:0\n", 87 nil, 88 }, 89 { 90 0xffffffff81a2aff9, 91 "0xffffffff81a2aff9\n" + 92 "devpts_get_priv\n" + 93 "fs/devpts/inode.c:588 (discriminator 3)\n", 94 []Frame{ 95 { 96 PC: 0xffffffff81a2aff9, 97 Func: "devpts_get_priv", 98 File: "fs/devpts/inode.c", 99 Line: 588, 100 Inline: false, 101 }, 102 }, 103 }, 104 } 105 106 // Stub addr2line. 107 inputr, inputw, err := os.Pipe() 108 if err != nil { 109 t.Fatal(err) 110 } 111 defer inputr.Close() 112 defer inputw.Close() 113 outputr, outputw, err := os.Pipe() 114 if err != nil { 115 t.Fatal(err) 116 } 117 defer outputr.Close() 118 done := make(chan error) 119 go func() { 120 s := bufio.NewScanner(inputr) 121 loop: 122 for s.Scan() { 123 pc, err := strconv.ParseUint(s.Text(), 0, 64) 124 if err != nil { 125 outputw.Close() 126 done <- fmt.Errorf("got unexpected pc: %v", s.Text()) 127 return 128 } 129 for _, addr := range addresses { 130 if pc == addr.pc { 131 outputw.Write([]byte(addr.resp)) 132 continue loop 133 } 134 } 135 outputw.Close() 136 done <- fmt.Errorf("got unexpected pc: 0x%x", pc) 137 return 138 } 139 outputw.Write([]byte("DONE\n")) 140 outputw.Close() 141 close(done) 142 }() 143 defer func() { 144 inputw.Close() 145 if err := <-done; err != nil { 146 t.Fatal(err) 147 } 148 }() 149 150 // First, symbolize all PCs one-by-one. 151 input := bufio.NewWriter(inputw) 152 scanner := bufio.NewScanner(outputr) 153 var interner Interner 154 var allPCs []uint64 155 var allFrames []Frame 156 for _, addr := range addresses { 157 frames, err := symbolize(&interner, input, scanner, []uint64{addr.pc}) 158 if err != nil { 159 t.Fatalf("got error: %v", err) 160 } 161 if !reflect.DeepEqual(addr.frames, frames) { 162 t.Fatalf("want frames:\n%+v\ngot:\n%+v", addr.frames, frames) 163 } 164 allPCs = append(allPCs, addr.pc) 165 allFrames = append(allFrames, frames...) 166 } 167 168 // Symbolize PCs in 2 groups. 169 for i := 0; i <= len(addresses); i++ { 170 frames, err := symbolize(&interner, input, scanner, allPCs[:i]) 171 if err != nil { 172 t.Fatalf("got error: %v", err) 173 } 174 frames2, err := symbolize(&interner, input, scanner, allPCs[i:]) 175 if err != nil { 176 t.Fatalf("got error: %v", err) 177 } 178 frames = append(frames, frames2...) 179 if !reflect.DeepEqual(allFrames, frames) { 180 t.Fatalf("want frames:\n%+v\ngot:\n%+v", allFrames, frames) 181 } 182 } 183 184 // Symbolize a huge pile of PCs (test for pipe overflows). 185 lots := make([]uint64, 1e4) 186 for i := range lots { 187 lots[i] = addresses[0].pc 188 } 189 frames, err := symbolize(&interner, input, scanner, lots) 190 if err != nil { 191 t.Fatalf("got error: %v", err) 192 } 193 if want := len(lots) * len(addresses[0].frames); want != len(frames) { 194 t.Fatalf("want %v frames, got %v", want, len(frames)) 195 } 196 }