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