Home | History | Annotate | Download | only in symbolz
      1 // Copyright 2014 Google Inc. All Rights Reserved.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 package symbolz
     16 
     17 import (
     18 	"fmt"
     19 	"strings"
     20 	"testing"
     21 
     22 	"github.com/google/pprof/internal/plugin"
     23 	"github.com/google/pprof/internal/proftest"
     24 	"github.com/google/pprof/profile"
     25 )
     26 
     27 func TestSymbolzURL(t *testing.T) {
     28 	for try, want := range map[string]string{
     29 		"http://host:8000/profilez":                                               "http://host:8000/symbolz",
     30 		"http://host:8000/profilez?seconds=5":                                     "http://host:8000/symbolz",
     31 		"http://host:8000/profilez?seconds=5&format=proto":                        "http://host:8000/symbolz",
     32 		"http://host:8000/heapz?format=legacy":                                    "http://host:8000/symbolz",
     33 		"http://host:8000/debug/pprof/profile":                                    "http://host:8000/debug/pprof/symbol",
     34 		"http://host:8000/debug/pprof/profile?seconds=10":                         "http://host:8000/debug/pprof/symbol",
     35 		"http://host:8000/debug/pprof/heap":                                       "http://host:8000/debug/pprof/symbol",
     36 		"http://some.host:8080/some/deeper/path/debug/pprof/endpoint?param=value": "http://some.host:8080/some/deeper/path/debug/pprof/symbol",
     37 	} {
     38 		if got := symbolz(try); got != want {
     39 			t.Errorf(`symbolz(%s)=%s, want "%s"`, try, got, want)
     40 		}
     41 	}
     42 }
     43 
     44 func TestSymbolize(t *testing.T) {
     45 	s := plugin.MappingSources{
     46 		"buildid": []struct {
     47 			Source string
     48 			Start  uint64
     49 		}{
     50 			{Source: "http://localhost:80/profilez"},
     51 		},
     52 	}
     53 
     54 	for _, hasFunctions := range []bool{false, true} {
     55 		for _, force := range []bool{false, true} {
     56 			p := testProfile(hasFunctions)
     57 
     58 			if err := Symbolize(p, force, s, fetchSymbols, &proftest.TestUI{T: t}); err != nil {
     59 				t.Errorf("symbolz: %v", err)
     60 				continue
     61 			}
     62 			var wantSym, wantNoSym []*profile.Location
     63 			if force || !hasFunctions {
     64 				wantNoSym = p.Location[:1]
     65 				wantSym = p.Location[1:]
     66 			} else {
     67 				wantNoSym = p.Location
     68 			}
     69 
     70 			if err := checkSymbolized(wantSym, true); err != nil {
     71 				t.Errorf("symbolz hasFns=%v force=%v: %v", hasFunctions, force, err)
     72 			}
     73 			if err := checkSymbolized(wantNoSym, false); err != nil {
     74 				t.Errorf("symbolz hasFns=%v force=%v: %v", hasFunctions, force, err)
     75 			}
     76 		}
     77 	}
     78 }
     79 
     80 func testProfile(hasFunctions bool) *profile.Profile {
     81 	m := []*profile.Mapping{
     82 		{
     83 			ID:           1,
     84 			Start:        0x1000,
     85 			Limit:        0x5000,
     86 			BuildID:      "buildid",
     87 			HasFunctions: hasFunctions,
     88 		},
     89 	}
     90 	p := &profile.Profile{
     91 		Location: []*profile.Location{
     92 			{ID: 1, Mapping: m[0], Address: 0x1000},
     93 			{ID: 2, Mapping: m[0], Address: 0x2000},
     94 			{ID: 3, Mapping: m[0], Address: 0x3000},
     95 			{ID: 4, Mapping: m[0], Address: 0x4000},
     96 		},
     97 		Mapping: m,
     98 	}
     99 
    100 	return p
    101 }
    102 
    103 func checkSymbolized(locs []*profile.Location, wantSymbolized bool) error {
    104 	for _, loc := range locs {
    105 		if !wantSymbolized && len(loc.Line) != 0 {
    106 			return fmt.Errorf("unexpected symbolization for %#x: %v", loc.Address, loc.Line)
    107 		}
    108 		if wantSymbolized {
    109 			if len(loc.Line) != 1 {
    110 				return fmt.Errorf("expected symbolization for %#x: %v", loc.Address, loc.Line)
    111 			}
    112 			address := loc.Address - loc.Mapping.Start
    113 			if got, want := loc.Line[0].Function.Name, fmt.Sprintf("%#x", address); got != want {
    114 				return fmt.Errorf("symbolz %#x, got %s, want %s", address, got, want)
    115 			}
    116 		}
    117 	}
    118 	return nil
    119 }
    120 
    121 func fetchSymbols(source, post string) ([]byte, error) {
    122 	var symbolz string
    123 
    124 	addresses := strings.Split(post, "+")
    125 	// Do not symbolize the first symbol.
    126 	for _, address := range addresses[1:] {
    127 		symbolz += fmt.Sprintf("%s\t%s\n", address, address)
    128 	}
    129 	return []byte(symbolz), nil
    130 }
    131