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  }