|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074 |
- // Copyright 2018 Google Inc. All Rights Reserved.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
-
- // +build linux
-
- package peek_test
-
- import (
- "flag"
- "fmt"
- "log"
- "os"
- "os/exec"
- "reflect"
- "regexp"
- "sync"
- "testing"
-
- "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug"
- "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/local"
- "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/remote"
- )
-
- var expectedVarValues = map[string]interface{}{
- `main.Z_bool_false`: false,
- `main.Z_bool_true`: true,
- `main.Z_complex128`: complex128(1.987654321 - 2.987654321i),
- `main.Z_complex64`: complex64(1.54321 + 2.54321i),
- `main.Z_float32`: float32(1.54321),
- `main.Z_float64`: float64(1.987654321),
- `main.Z_int16`: int16(-32321),
- `main.Z_int32`: int32(-1987654321),
- `main.Z_int64`: int64(-9012345678987654321),
- `main.Z_int8`: int8(-121),
- `main.Z_uint16`: uint16(54321),
- `main.Z_uint32`: uint32(3217654321),
- `main.Z_uint64`: uint64(12345678900987654321),
- `main.Z_uint8`: uint8(231),
- }
-
- // TODO: the string forms of some types we're testing aren't stable
- var expectedVars = map[string]string{
- `main.Z_array`: `[5]int8{-121, 121, 3, 2, 1}`,
- `main.Z_array_empty`: `[0]int8{}`,
- `main.Z_bool_false`: `false`,
- `main.Z_bool_true`: `true`,
- `main.Z_channel`: `(chan int16 0xX)`,
- `main.Z_channel_2`: `(chan int16 0xX)`,
- `main.Z_channel_buffered`: `(chan int16 0xX [6/10])`,
- `main.Z_channel_nil`: `(chan int16 <nil>)`,
- `main.Z_array_of_empties`: `[2]{}{{} {}, ({} 0xX)}`,
- `main.Z_complex128`: `(1.987654321-2.987654321i)`,
- `main.Z_complex64`: `(1.54321+2.54321i)`,
- `main.Z_float32`: `1.54321`,
- `main.Z_float64`: `1.987654321`,
- `main.Z_func_int8_r_int8`: `func(int8, *int8) void @0xX `,
- `main.Z_func_int8_r_pint8`: `func(int8, **int8) void @0xX `,
- `main.Z_func_bar`: `func(*main.FooStruct) void @0xX `,
- `main.Z_func_nil`: `func(int8, *int8) void @0xX `,
- `main.Z_int`: `-21`,
- `main.Z_int16`: `-32321`,
- `main.Z_int32`: `-1987654321`,
- `main.Z_int64`: `-9012345678987654321`,
- `main.Z_int8`: `-121`,
- `main.Z_int_typedef`: `88`,
- `main.Z_interface`: `("*main.FooStruct", 0xX)`,
- `main.Z_interface_nil`: `(<nil>, <nil>)`,
- `main.Z_interface_typed_nil`: `("*main.FooStruct", <nil>)`,
- `main.Z_map`: `map[-21:3.54321]`,
- `main.Z_map_2`: `map[1024:1]`,
- `main.Z_map_3`: `map[1024:1 512:-1]`,
- `main.Z_map_empty`: `map[]`,
- `main.Z_map_nil`: `map[]`,
- `main.Z_pointer`: `0xX`,
- `main.Z_pointer_nil`: `0x0`,
- `main.Z_slice`: `[]uint8{115, 108, 105, 99, 101}`,
- `main.Z_slice_2`: `[]int8{-121, 121}`,
- `main.Z_slice_nil`: `[]uint8{}`,
- `main.Z_string`: `"I'm a string"`,
- `main.Z_struct`: `main.FooStruct {21, "hi"}`,
- `main.Z_uint`: `21`,
- `main.Z_uint16`: `54321`,
- `main.Z_uint32`: `3217654321`,
- `main.Z_uint64`: `12345678900987654321`,
- `main.Z_uint8`: `231`,
- `main.Z_uintptr`: `21`,
- `main.Z_unsafe_pointer`: `0xX`,
- `main.Z_unsafe_pointer_nil`: `0x0`,
- }
-
- // expectedEvaluate contains expected results of the debug.Evaluate function.
- // A nil value indicates that an error is expected.
- var expectedEvaluate = map[string]debug.Value{
- `x`: int16(42),
- `local_array`: debug.Array{42, 42, 5, 8},
- `local_channel`: debug.Channel{42, 42, 42, 0, 0, 2, 0},
- `local_channel_buffered`: debug.Channel{42, 42, 42, 6, 10, 2, 8},
- `local_map`: debug.Map{42, 42, 1},
- `local_map_2`: debug.Map{42, 42, 1},
- `local_map_3`: debug.Map{42, 42, 2},
- `local_map_empty`: debug.Map{42, 42, 0},
- `x + 5`: int16(47),
- `x - 5`: int16(37),
- `x / 5`: int16(8),
- `x % 5`: int16(2),
- `x & 2`: int16(2),
- `x | 1`: int16(43),
- `x ^ 3`: int16(41),
- `5 + x`: int16(47),
- `5 - x`: int16(-37),
- `100 / x`: int16(2),
- `100 % x`: int16(16),
- `2 & x`: int16(2),
- `1 | x`: int16(43),
- `3 ^ x`: int16(41),
- `12`: 12,
- `+42`: 42,
- `23i`: 23i,
- `34.0`: 34.0,
- `34.5`: 34.5,
- `1e5`: 100000.0,
- `0x42`: 66,
- `'c'`: 'c',
- `"de"`: debug.String{2, `de`},
- "`ef`": debug.String{2, `ef`},
- `"de" + "fg"`: debug.String{4, `defg`},
- `/* comment */ -5`: -5,
- `false`: false,
- `true`: true,
- `!false`: true,
- `!true`: false,
- `5 + 5`: 10,
- `true || false`: true,
- `false || false`: false,
- `true && false`: false,
- `true && true`: true,
- `!(5 > 8)`: true,
- `10 + 'a'`: 'k',
- `10 + 10.5`: 20.5,
- `10 + 10.5i`: 10 + 10.5i,
- `'a' + 10.5`: 107.5,
- `'a' + 10.5i`: 97 + 10.5i,
- `10.5 + 20.5i`: 10.5 + 20.5i,
- `10 * 20`: 200,
- `10.0 - 20.5`: -10.5,
- `(6 + 8i) * 4`: 24 + 32i,
- `(6 + 8i) * (1 + 1i)`: -2 + 14i,
- `(6 + 8i) * (6 - 8i)`: complex128(100),
- `(6 + 8i) / (3 + 4i)`: complex128(2),
- `local_array[2]`: int8(3),
- `&local_array[1]`: debug.Pointer{42, 42},
- `local_map[-21]`: float32(3.54321),
- `local_map[+21]`: float32(0),
- `local_map_3[1024]`: int8(1),
- `local_map_3[512]`: int8(-1),
- `local_map_empty[21]`: float32(0),
- `"hello"[2]`: uint8('l'),
- `local_array[1:3][1]`: int8(3),
- `local_array[0:4][2:3][0]`: int8(3),
- `local_array[:]`: debug.Slice{debug.Array{42, 42, 5, 8}, 5},
- `local_array[:2]`: debug.Slice{debug.Array{42, 42, 2, 8}, 5},
- `local_array[2:]`: debug.Slice{debug.Array{42, 42, 3, 8}, 3},
- `local_array[1:3]`: debug.Slice{debug.Array{42, 42, 2, 8}, 4},
- `local_array[:3:4]`: debug.Slice{debug.Array{42, 42, 3, 8}, 4},
- `local_array[1:3:4]`: debug.Slice{debug.Array{42, 42, 2, 8}, 3},
- `local_array[1:][1:][1:]`: debug.Slice{debug.Array{42, 42, 2, 8}, 2},
- `(&local_array)[:]`: debug.Slice{debug.Array{42, 42, 5, 8}, 5},
- `(&local_array)[:2]`: debug.Slice{debug.Array{42, 42, 2, 8}, 5},
- `(&local_array)[2:]`: debug.Slice{debug.Array{42, 42, 3, 8}, 3},
- `(&local_array)[1:3]`: debug.Slice{debug.Array{42, 42, 2, 8}, 4},
- `(&local_array)[:3:4]`: debug.Slice{debug.Array{42, 42, 3, 8}, 4},
- `(&local_array)[1:3:4]`: debug.Slice{debug.Array{42, 42, 2, 8}, 3},
- `lookup("main.Z_array")`: debug.Array{42, 42, 5, 8},
- `lookup("main.Z_array_empty")`: debug.Array{42, 42, 0, 8},
- `lookup("main.Z_bool_false")`: false,
- `lookup("main.Z_bool_true")`: true,
- `lookup("main.Z_channel")`: debug.Channel{42, 42, 42, 0, 0, 2, 0},
- `lookup("main.Z_channel_buffered")`: debug.Channel{42, 42, 42, 6, 10, 2, 8},
- `lookup("main.Z_channel_nil")`: debug.Channel{42, 0, 0, 0, 0, 2, 0},
- `lookup("main.Z_array_of_empties")`: debug.Array{42, 42, 2, 0},
- `lookup("main.Z_complex128")`: complex128(1.987654321 - 2.987654321i),
- `lookup("main.Z_complex64")`: complex64(1.54321 + 2.54321i),
- `lookup("main.Z_float32")`: float32(1.54321),
- `lookup("main.Z_float64")`: float64(1.987654321),
- `lookup("main.Z_func_int8_r_int8")`: debug.Func{42},
- `lookup("main.Z_func_int8_r_pint8")`: debug.Func{42},
- `lookup("main.Z_func_bar")`: debug.Func{42},
- `lookup("main.Z_func_nil")`: debug.Func{0},
- `lookup("main.Z_int")`: -21,
- `lookup("main.Z_int16")`: int16(-32321),
- `lookup("main.Z_int32")`: int32(-1987654321),
- `lookup("main.Z_int64")`: int64(-9012345678987654321),
- `lookup("main.Z_int8")`: int8(-121),
- `lookup("main.Z_int_typedef")`: int16(88),
- `lookup("main.Z_interface")`: debug.Interface{},
- `lookup("main.Z_interface_nil")`: debug.Interface{},
- `lookup("main.Z_interface_typed_nil")`: debug.Interface{},
- `lookup("main.Z_map")`: debug.Map{42, 42, 1},
- `lookup("main.Z_map_2")`: debug.Map{42, 42, 1},
- `lookup("main.Z_map_3")`: debug.Map{42, 42, 2},
- `lookup("main.Z_map_empty")`: debug.Map{42, 42, 0},
- `lookup("main.Z_map_nil")`: debug.Map{42, 42, 0},
- `lookup("main.Z_pointer")`: debug.Pointer{42, 42},
- `lookup("main.Z_pointer_nil")`: debug.Pointer{42, 0},
- `lookup("main.Z_slice")`: debug.Slice{debug.Array{42, 42, 5, 8}, 5},
- `lookup("main.Z_slice_2")`: debug.Slice{debug.Array{42, 42, 2, 8}, 5},
- `lookup("main.Z_slice_nil")`: debug.Slice{debug.Array{42, 0, 0, 8}, 0},
- `lookup("main.Z_string")`: debug.String{12, `I'm a string`},
- `lookup("main.Z_struct")`: debug.Struct{[]debug.StructField{{"a", debug.Var{}}, {"b", debug.Var{}}}},
- `lookup("main.Z_uint")`: uint(21),
- `lookup("main.Z_uint16")`: uint16(54321),
- `lookup("main.Z_uint32")`: uint32(3217654321),
- `lookup("main.Z_uint64")`: uint64(12345678900987654321),
- `lookup("main.Z_uint8")`: uint8(231),
- `lookup("main.Z_uintptr")`: uint(21),
- `lookup("main.Z_unsafe_pointer")`: debug.Pointer{0, 42},
- `lookup("main.Z_unsafe_pointer_nil")`: debug.Pointer{0, 0},
- `lookup("main.Z_int") + lookup("main.Z_int")`: -42,
- `lookup("main.Z_int16") < 0`: true,
- `lookup("main.Z_uint32") + lookup("main.Z_uint32")`: uint32(2140341346),
- `lookup("main.Z_bool_true") || lookup("main.Z_bool_false")`: true,
- `lookup("main.Z_bool_true") && lookup("main.Z_bool_false")`: false,
- `lookup("main.Z_bool_false") || lookup("main.Z_bool_false")`: false,
- `!lookup("main.Z_bool_true")`: false,
- `!lookup("main.Z_bool_false")`: true,
- `lookup("main.Z_array")[2]`: int8(3),
- `lookup("main.Z_array")[1:3][1]`: int8(3),
- `lookup("main.Z_array")[0:4][2:3][0]`: int8(3),
- `lookup("main.Z_array_of_empties")[0]`: debug.Struct{},
- `lookup("main.Z_complex128") * 10.0`: complex128(19.87654321 - 29.87654321i),
- `lookup("main.Z_complex64") * 0.1`: complex64(0.154321 + 0.254321i),
- `lookup("main.Z_float32") * 10.0`: float32(15.4321),
- `lookup("main.Z_float64") * 0.1`: float64(0.1987654321),
- `lookup("main.Z_int") + 1`: int(-20),
- `lookup("main.Z_int16") - 10`: int16(-32331),
- `lookup("main.Z_int32") / 10`: int32(-198765432),
- `lookup("main.Z_int64") / 10`: int64(-901234567898765432),
- `lookup("main.Z_int8") + 10`: int8(-111),
- `lookup("main.Z_map")[-21]`: float32(3.54321),
- `lookup("main.Z_map")[+21]`: float32(0),
- `lookup("main.Z_map_empty")[21]`: float32(0),
- `lookup("main.Z_slice")[1]`: uint8(108),
- `lookup("main.Z_slice_2")[1]`: int8(121),
- `lookup("main.Z_slice")[1:5][0:3][1]`: uint8('i'),
- `lookup("main.Z_array")[1:3:4]`: debug.Slice{debug.Array{42, 42, 2, 8}, 3},
- `(&lookup("main.Z_array"))[1:3:4]`: debug.Slice{debug.Array{42, 42, 2, 8}, 3},
- `lookup("main.Z_string") + "!"`: debug.String{13, `I'm a string!`},
- `lookup("main.Z_struct").a`: 21,
- `(&lookup("main.Z_struct")).a`: 21,
- `lookup("main.Z_uint")/10`: uint(2),
- `lookup("main.Z_uint16")/10`: uint16(5432),
- `lookup("main.Z_uint32")/10`: uint32(321765432),
- `lookup("main.Z_uint64")/10`: uint64(1234567890098765432),
- `lookup("main.Z_uint8")/10`: uint8(23),
- `lookup("main.Z_pointer").a`: 21,
- `(*lookup("main.Z_pointer")).a`: 21,
- `(&*lookup("main.Z_pointer")).a`: 21,
- `lookup("main.Z_pointer").b`: debug.String{2, `hi`},
- `(*lookup("main.Z_pointer")).b`: debug.String{2, `hi`},
- `(&*lookup("main.Z_pointer")).b`: debug.String{2, `hi`},
- `lookup("main.Z_map_nil")[32]`: float32(0),
- `&lookup("main.Z_int16")`: debug.Pointer{42, 42},
- `&lookup("main.Z_array")[1]`: debug.Pointer{42, 42},
- `&lookup("main.Z_slice")[1]`: debug.Pointer{42, 42},
- `*&lookup("main.Z_int16")`: int16(-32321),
- `*&*&*&*&lookup("main.Z_int16")`: int16(-32321),
- `lookup("time.Local")`: debug.Pointer{42, 42},
- `5 + false`: nil,
- ``: nil,
- `x + ""`: nil,
- `x / 0`: nil,
- `0 / 0`: nil,
- `'a' / ('a'-'a')`: nil,
- `0.0 / 0.0`: nil,
- `3i / 0.0`: nil,
- `x % 0`: nil,
- `0 % 0`: nil,
- `'a' % ('a'-'a')`: nil,
- `local_array[-2] + 1`: nil,
- `local_array[22] + 1`: nil,
- `local_slice[-2] + 1`: nil,
- `local_slice[22] + 1`: nil,
- `local_string[-2]`: nil,
- `local_string[22]`: nil,
- `"hello"[-2]`: nil,
- `"hello"[22]`: nil,
- `local_pointer_nil.a`: nil,
- `(local_struct).c`: nil,
- `(&local_struct).c`: nil,
- `(*local_pointer).c`: nil,
- `lookup("not a real symbol")`: nil,
- `lookup("x")`: nil,
- `lookup(x)`: nil,
- `lookup(42)`: nil,
- }
-
- func isHex(r uint8) bool {
- switch {
- case '0' <= r && r <= '9':
- return true
- case 'a' <= r && r <= 'f':
- return true
- case 'A' <= r && r <= 'F':
- return true
- default:
- return false
- }
- }
-
- // structRE is used by matches to remove 'struct ' from type names, which is not
- // output by every version of the compiler.
- var structRE = regexp.MustCompile("struct *")
-
- // Check s matches the pattern in p.
- // An 'X' in p greedily matches one or more hex characters in s.
- func matches(p, s string) bool {
- // Remove 'struct' and following spaces from s.
- s = structRE.ReplaceAllString(s, "")
- j := 0
- for i := 0; i < len(p); i++ {
- if j == len(s) {
- return false
- }
- c := p[i]
- if c == 'X' {
- if !isHex(s[j]) {
- return false
- }
- for j < len(s) && isHex(s[j]) {
- j++
- }
- continue
- }
- if c != s[j] {
- return false
- }
- j++
- }
- return j == len(s)
- }
-
- const (
- proxySrc = "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/cmd/debugproxy"
- traceeSrc = "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/tests/peek/testdata"
- )
-
- var (
- // Locations of the proxy and tracee executables.
- proxyBinary = "./debugproxy.out"
- traceeBinary = "./tracee.out"
- // Onces that ensure initProxy and initTracee are called at most once.
- proxyOnce sync.Once
- traceeOnce sync.Once
- // Flags for setting the location of the proxy and tracee, so they don't need to be built.
- proxyFlag = flag.String("proxy", "", "Location of debugproxy. If empty, proxy will be built.")
- traceeFlag = flag.String("target", "", "Location of target. If empty, target will be built.")
- // Executables this test has built, which will be removed on completion of the tests.
- filesToRemove []string
- )
-
- func TestMain(m *testing.M) {
- flag.Parse()
- x := m.Run()
- for _, f := range filesToRemove {
- os.Remove(f)
- }
- os.Exit(x)
- }
-
- func run(name string, args ...string) error {
- cmd := exec.Command(name, args...)
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
- return cmd.Run()
- }
-
- func initProxy() {
- if *proxyFlag != "" {
- proxyBinary = *proxyFlag
- remote.DebugproxyCmd = proxyBinary
- return
- }
- if err := run("go", "build", "-o", proxyBinary, proxySrc); err != nil {
- log.Fatalf("couldn't build proxy: %v", err)
- }
- filesToRemove = append(filesToRemove, proxyBinary)
- remote.DebugproxyCmd = proxyBinary
- }
-
- func initTracee() {
- if *traceeFlag != "" {
- traceeBinary = *traceeFlag
- return
- }
- if err := run("go", "build", "-o", traceeBinary, traceeSrc); err != nil {
- log.Fatalf("couldn't build target: %v", err)
- }
- filesToRemove = append(filesToRemove, traceeBinary)
- }
-
- func TestLocalProgram(t *testing.T) {
- t.Skip("Fails looking for runtime.lessstack for some reason")
- traceeOnce.Do(initTracee)
- prog, err := local.New(traceeBinary)
- if err != nil {
- t.Fatal("local.New:", err)
- }
- testProgram(t, prog)
- }
-
- func TestRemoteProgram(t *testing.T) {
- t.Skip("Fails looking for runtime.lessstack for some reason")
- traceeOnce.Do(initTracee)
- proxyOnce.Do(initProxy)
- prog, err := remote.New("localhost", traceeBinary)
- if err != nil {
- t.Fatal("remote.New:", err)
- }
- testProgram(t, prog)
- }
-
- func testProgram(t *testing.T, prog debug.Program) {
- _, err := prog.Run("some", "arguments")
- if err != nil {
- log.Fatalf("Run: %v", err)
- }
-
- pcs, err := prog.BreakpointAtFunction("main.foo")
- if err != nil {
- log.Fatalf("BreakpointAtFunction: %v", err)
- }
- fmt.Printf("breakpoints set at %x\n", pcs)
-
- _, err = prog.Resume()
- if err != nil {
- log.Fatalf("Resume: %v", err)
- }
-
- gs, err := prog.Goroutines()
- if err != nil {
- t.Fatalf("Goroutines(): got error %s", err)
- }
- for _, g := range gs {
- fmt.Println(g)
- for _, f := range g.StackFrames {
- fmt.Println(f)
- }
- }
-
- frames, err := prog.Frames(100)
- if err != nil {
- log.Fatalf("prog.Frames error: %v", err)
- }
- fmt.Printf("%#v\n", frames)
- if len(frames) == 0 {
- t.Fatalf("no stack frames returned")
- }
- if frames[0].Function != "main.foo" {
- t.Errorf("function name: got %s expected main.foo", frames[0].Function)
- }
- if len(frames[0].Params) != 2 {
- t.Errorf("got %d parameters, expected 2", len(frames[0].Params))
- } else {
- x := frames[0].Params[0]
- y := frames[0].Params[1]
- if x.Name != "x" {
- x, y = y, x
- }
- if x.Name != "x" {
- t.Errorf("parameter name: got %s expected x", x.Name)
- }
- if y.Name != "y" {
- t.Errorf("parameter name: got %s expected y", y.Name)
- }
- if val, err := prog.Value(x.Var); err != nil {
- t.Errorf("value of x: %s", err)
- } else if val != int16(42) {
- t.Errorf("value of x: got %T(%v) expected int16(42)", val, val)
- }
- if val, err := prog.Value(y.Var); err != nil {
- t.Errorf("value of y: %s", err)
- } else if val != float32(1.5) {
- t.Errorf("value of y: got %T(%v) expected float32(1.5)", val, val)
- }
- }
-
- varnames, err := prog.Eval(`re:main\.Z_.*`)
- if err != nil {
- log.Fatalf("prog.Eval error: %v", err)
- }
-
- // Evaluate each of the variables found above, and check they match
- // expectedVars.
- seen := make(map[string]bool)
- for _, v := range varnames {
- val, err := prog.Eval("val:" + v)
- if err != nil {
- log.Fatalf("prog.Eval error for %s: %v", v, err)
- } else {
- fmt.Printf("%s = %v\n", v, val)
- if seen[v] {
- log.Fatalf("repeated variable %s\n", v)
- }
- seen[v] = true
- if len(val) != 1 {
- log.Fatalf("should be one value for %s\n", v)
- }
- expected, ok := expectedVars[v]
- if !ok {
- log.Fatalf("unexpected variable %s\n", v)
- } else {
- if !matches(expected, val[0]) {
- log.Fatalf("expected %s = %s\n", v, expected)
- }
- }
- }
- }
- for v, e := range expectedVars {
- if !seen[v] {
- log.Fatalf("didn't get %s = %s\n", v, e)
- }
- }
-
- // Remove the breakpoint at main.foo.
- err = prog.DeleteBreakpoints(pcs)
- if err != nil {
- log.Fatalf("DeleteBreakpoints: %v", err)
- }
-
- // Set a breakpoint at line 125, resume, and check we stopped there.
- pcsLine125, err := prog.BreakpointAtLine("testdata/main.go", 125)
- if err != nil {
- t.Fatal("BreakpointAtLine:", err)
- }
- status, err := prog.Resume()
- if err != nil {
- log.Fatalf("Resume: %v", err)
- }
- stoppedAt := func(pcs []uint64) bool {
- for _, pc := range pcs {
- if status.PC == pc {
- return true
- }
- }
- return false
- }
- if !stoppedAt(pcsLine125) {
- t.Errorf("stopped at %X; expected one of %X.", status.PC, pcsLine125)
- }
-
- for k, v := range expectedEvaluate {
- val, err := prog.Evaluate(k)
- if v == nil {
- if err == nil {
- t.Errorf("got Evaluate(%s) = %v, expected error", k, val)
- }
- continue
- }
- if err != nil {
- t.Errorf("Evaluate(%s): got error %s, expected %v", k, err, v)
- continue
- }
- typ := reflect.TypeOf(v)
- if typ != reflect.TypeOf(val) && typ != reflect.TypeOf(int(0)) && typ != reflect.TypeOf(uint(0)) {
- t.Errorf("got Evaluate(%s) = %T(%v), expected %T(%v)", k, val, val, v, v)
- continue
- }
-
- // For types with fields like Address, TypeID, etc., we can't know the exact
- // value, so we only test whether those fields are zero or not.
- switch v := v.(type) {
- default:
- if v != val {
- t.Errorf("got Evaluate(%s) = %T(%v), expected %T(%v)", k, val, val, v, v)
- }
- case debug.Array:
- val := val.(debug.Array)
- if v.ElementTypeID == 0 && val.ElementTypeID != 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected zero ElementTypeID", k, val)
- }
- if v.ElementTypeID != 0 && val.ElementTypeID == 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected non-zero ElementTypeID", k, val)
- }
- if v.Address == 0 && val.Address != 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected zero Address", k, val)
- }
- if v.Address != 0 && val.Address == 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected non-zero Address", k, val)
- }
- case debug.Slice:
- val := val.(debug.Slice)
- if v.ElementTypeID == 0 && val.ElementTypeID != 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected zero ElementTypeID", k, val)
- }
- if v.ElementTypeID != 0 && val.ElementTypeID == 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected non-zero ElementTypeID", k, val)
- }
- if v.Address == 0 && val.Address != 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected zero Address", k, val)
- }
- if v.Address != 0 && val.Address == 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected non-zero Address", k, val)
- }
- case debug.Map:
- val := val.(debug.Map)
- if v.TypeID == 0 && val.TypeID != 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected zero TypeID", k, val)
- }
- if v.TypeID != 0 && val.TypeID == 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected non-zero TypeID", k, val)
- }
- if v.Address == 0 && val.Address != 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected zero Address", k, val)
- }
- if v.Address != 0 && val.Address == 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected non-zero Address", k, val)
- }
- case debug.Pointer:
- val := val.(debug.Pointer)
- if v.TypeID == 0 && val.TypeID != 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected zero TypeID", k, val)
- }
- if v.TypeID != 0 && val.TypeID == 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected non-zero TypeID", k, val)
- }
- if v.Address == 0 && val.Address != 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected zero Address", k, val)
- }
- if v.Address != 0 && val.Address == 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected non-zero Address", k, val)
- }
- case debug.Channel:
- val := val.(debug.Channel)
- if v.ElementTypeID == 0 && val.ElementTypeID != 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected zero ElementTypeID", k, val)
- }
- if v.ElementTypeID != 0 && val.ElementTypeID == 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected non-zero ElementTypeID", k, val)
- }
- if v.Address == 0 && val.Address != 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected zero Address", k, val)
- }
- if v.Address != 0 && val.Address == 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected non-zero Address", k, val)
- }
- if v.Buffer == 0 && val.Buffer != 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected zero Buffer", k, val)
- }
- if v.Buffer != 0 && val.Buffer == 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected non-zero Buffer", k, val)
- }
- case debug.Struct:
- val := val.(debug.Struct)
- if len(v.Fields) != len(val.Fields) {
- t.Errorf("got Evaluate(%s) = %T(%v), expected %T(%v)", k, val, val, v, v)
- break
- }
- for i := range v.Fields {
- a := v.Fields[i].Name
- b := val.Fields[i].Name
- if a != b {
- t.Errorf("Evaluate(%s): field name mismatch: %s vs %s", k, a, b)
- break
- }
- }
- case debug.Func:
- val := val.(debug.Func)
- if v.Address == 0 && val.Address != 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected zero Address", k, val)
- }
- if v.Address != 0 && val.Address == 0 {
- t.Errorf("got Evaluate(%s) = %+v, expected non-zero Address", k, val)
- }
- case int:
- // ints in a remote program can be returned as int32 or int64
- switch val := val.(type) {
- case int32:
- if val != int32(v) {
- t.Errorf("got Evaluate(%s) = %T(%v), expected %v", k, val, val, v)
- }
- case int64:
- if val != int64(v) {
- t.Errorf("got Evaluate(%s) = %T(%v), expected %v", k, val, val, v)
- }
- default:
- t.Errorf("got Evaluate(%s) = %T(%v), expected %T(%v)", k, val, val, v, v)
- }
- case uint:
- // uints in a remote program can be returned as uint32 or uint64
- switch val := val.(type) {
- case uint32:
- if val != uint32(v) {
- t.Errorf("got Evaluate(%s) = %T(%v), expected %v", k, val, val, v)
- }
- case uint64:
- if val != uint64(v) {
- t.Errorf("got Evaluate(%s) = %T(%v), expected %v", k, val, val, v)
- }
- default:
- t.Errorf("got Evaluate(%s) = %T(%v), expected %T(%v)", k, val, val, v, v)
- }
- }
- }
-
- // Evaluate a struct.
- v := `lookup("main.Z_struct")`
- val, err := prog.Evaluate(v)
- if err != nil {
- t.Fatalf("Evaluate: %s", err)
- }
- s, ok := val.(debug.Struct)
- if !ok {
- t.Fatalf("got Evaluate(%q) = %T(%v), expected debug.Struct", v, val, val)
- }
- // Check the values of its fields.
- if len(s.Fields) != 2 {
- t.Fatalf("got Evaluate(%q) = %+v, expected 2 fields", v, s)
- }
- if v0, err := prog.Value(s.Fields[0].Var); err != nil {
- t.Errorf("Value: %s", err)
- } else if v0 != int32(21) && v0 != int64(21) {
- t.Errorf("Value: got %T(%v), expected 21", v0, v0)
- }
- if v1, err := prog.Value(s.Fields[1].Var); err != nil {
- t.Errorf("Value: %s", err)
- } else if v1 != (debug.String{2, "hi"}) {
- t.Errorf("Value: got %T(%v), expected `hi`", v1, v1)
- }
-
- // Remove the breakpoint at line 125, set a breakpoint at main.f1 and main.f2,
- // then delete the breakpoint at main.f1. Resume, then check we stopped at
- // main.f2.
- err = prog.DeleteBreakpoints(pcsLine125)
- if err != nil {
- log.Fatalf("DeleteBreakpoints: %v", err)
- }
- pcs1, err := prog.BreakpointAtFunction("main.f1")
- if err != nil {
- log.Fatalf("BreakpointAtFunction: %v", err)
- }
- pcs2, err := prog.BreakpointAtFunction("main.f2")
- if err != nil {
- log.Fatalf("BreakpointAtFunction: %v", err)
- }
- err = prog.DeleteBreakpoints(pcs1)
- if err != nil {
- log.Fatalf("DeleteBreakpoints: %v", err)
- }
- status, err = prog.Resume()
- if err != nil {
- log.Fatalf("Resume: %v", err)
- }
- if !stoppedAt(pcs2) {
- t.Errorf("stopped at %X; expected one of %X.", status.PC, pcs2)
- }
-
- // Check we get the expected results calling VarByName then Value
- // for the variables in expectedVarValues.
- for name, exp := range expectedVarValues {
- if v, err := prog.VarByName(name); err != nil {
- t.Errorf("VarByName(%s): %s", name, err)
- } else if val, err := prog.Value(v); err != nil {
- t.Errorf("value of %s: %s", name, err)
- } else if val != exp {
- t.Errorf("value of %s: got %T(%v) want %T(%v)", name, val, val, exp, exp)
- }
- }
-
- // Check some error cases for VarByName and Value.
- if _, err = prog.VarByName("not a real name"); err == nil {
- t.Error("VarByName for invalid name: expected error")
- }
- if _, err = prog.Value(debug.Var{}); err == nil {
- t.Error("value of invalid var: expected error")
- }
- if v, err := prog.VarByName("main.Z_int16"); err != nil {
- t.Error("VarByName(main.Z_int16) error:", err)
- } else {
- v.Address = 0
- // v now has a valid type but a bad address.
- _, err = prog.Value(v)
- if err == nil {
- t.Error("value of invalid location: expected error")
- }
- }
-
- // checkValue tests that we can get a Var for a variable with the given name,
- // that we can then get the value of that Var, and that calling fn for that
- // value succeeds.
- checkValue := func(name string, fn func(val debug.Value) error) {
- if v, err := prog.VarByName(name); err != nil {
- t.Errorf("VarByName(%s): %s", name, err)
- } else if val, err := prog.Value(v); err != nil {
- t.Errorf("value of %s: %s", name, err)
- } else if err := fn(val); err != nil {
- t.Errorf("value of %s: %s", name, err)
- }
- }
-
- checkValue("main.Z_uintptr", func(val debug.Value) error {
- if val != uint32(21) && val != uint64(21) {
- // Z_uintptr should be an unsigned integer with size equal to the debugged
- // program's address size.
- return fmt.Errorf("got %T(%v) want 21", val, val)
- }
- return nil
- })
-
- checkValue("main.Z_int", func(val debug.Value) error {
- if val != int32(-21) && val != int64(-21) {
- return fmt.Errorf("got %T(%v) want -21", val, val)
- }
- return nil
- })
-
- checkValue("main.Z_uint", func(val debug.Value) error {
- if val != uint32(21) && val != uint64(21) {
- return fmt.Errorf("got %T(%v) want 21", val, val)
- }
- return nil
- })
-
- checkValue("main.Z_pointer", func(val debug.Value) error {
- if _, ok := val.(debug.Pointer); !ok {
- return fmt.Errorf("got %T(%v) expected Pointer", val, val)
- }
- return nil
- })
-
- checkValue("main.Z_pointer_nil", func(val debug.Value) error {
- if p, ok := val.(debug.Pointer); !ok {
- return fmt.Errorf("got %T(%v) expected Pointer", val, val)
- } else if p.Address != 0 {
- return fmt.Errorf("got %T(%v) expected nil pointer", val, val)
- }
- return nil
- })
-
- checkValue("main.Z_array", func(val debug.Value) error {
- a, ok := val.(debug.Array)
- if !ok {
- return fmt.Errorf("got %T(%v) expected Array", val, val)
- }
- if a.Len() != 5 {
- return fmt.Errorf("got array length %d expected 5", a.Len())
- }
- expected := [5]int8{-121, 121, 3, 2, 1}
- for i := uint64(0); i < 5; i++ {
- if v, err := prog.Value(a.Element(i)); err != nil {
- return fmt.Errorf("reading element %d: %s", i, err)
- } else if v != expected[i] {
- return fmt.Errorf("element %d: got %T(%v) want %T(%d)", i, v, v, expected[i], expected[i])
- }
- }
- return nil
- })
-
- checkValue("main.Z_slice", func(val debug.Value) error {
- s, ok := val.(debug.Slice)
- if !ok {
- return fmt.Errorf("got %T(%v) expected Slice", val, val)
- }
- if s.Len() != 5 {
- return fmt.Errorf("got slice length %d expected 5", s.Len())
- }
- expected := []uint8{115, 108, 105, 99, 101}
- for i := uint64(0); i < 5; i++ {
- if v, err := prog.Value(s.Element(i)); err != nil {
- return fmt.Errorf("reading element %d: %s", i, err)
- } else if v != expected[i] {
- return fmt.Errorf("element %d: got %T(%v) want %T(%d)", i, v, v, expected[i], expected[i])
- }
- }
- return nil
- })
-
- checkValue("main.Z_map_empty", func(val debug.Value) error {
- m, ok := val.(debug.Map)
- if !ok {
- return fmt.Errorf("got %T(%v) expected Map", val, val)
- }
- if m.Length != 0 {
- return fmt.Errorf("got map length %d expected 0", m.Length)
- }
- return nil
- })
-
- checkValue("main.Z_map_nil", func(val debug.Value) error {
- m, ok := val.(debug.Map)
- if !ok {
- return fmt.Errorf("got %T(%v) expected Map", val, val)
- }
- if m.Length != 0 {
- return fmt.Errorf("got map length %d expected 0", m.Length)
- }
- return nil
- })
-
- checkValue("main.Z_map_3", func(val debug.Value) error {
- m, ok := val.(debug.Map)
- if !ok {
- return fmt.Errorf("got %T(%v) expected Map", val, val)
- }
- if m.Length != 2 {
- return fmt.Errorf("got map length %d expected 2", m.Length)
- }
- keyVar0, valVar0, err := prog.MapElement(m, 0)
- if err != nil {
- return err
- }
- keyVar1, valVar1, err := prog.MapElement(m, 1)
- if err != nil {
- return err
- }
- key0, err := prog.Value(keyVar0)
- if err != nil {
- return err
- }
- key1, err := prog.Value(keyVar1)
- if err != nil {
- return err
- }
- val0, err := prog.Value(valVar0)
- if err != nil {
- return err
- }
- val1, err := prog.Value(valVar1)
- if err != nil {
- return err
- }
- // The map should contain 1024,1 and 512,-1 in some order.
- ok1 := key0 == int16(1024) && val0 == int8(1) && key1 == int16(512) && val1 == int8(-1)
- ok2 := key1 == int16(1024) && val1 == int8(1) && key0 == int16(512) && val0 == int8(-1)
- if !ok1 && !ok2 {
- return fmt.Errorf("got values (%d,%d) and (%d,%d), expected (1024,1) and (512,-1) in some order", key0, val0, key1, val1)
- }
- _, _, err = prog.MapElement(m, 2)
- if err == nil {
- return fmt.Errorf("MapElement: reading at a bad index succeeded, expected error")
- }
- return nil
- })
-
- checkValue("main.Z_string", func(val debug.Value) error {
- s, ok := val.(debug.String)
- if !ok {
- return fmt.Errorf("got %T(%v) expected String", val, val)
- }
- if s.Length != 12 {
- return fmt.Errorf("got string length %d expected 12", s.Length)
- }
- expected := "I'm a string"
- if s.String != expected {
- return fmt.Errorf("got %s expected %s", s.String, expected)
- }
- return nil
- })
-
- checkValue("main.Z_channel", func(val debug.Value) error {
- c, ok := val.(debug.Channel)
- if !ok {
- return fmt.Errorf("got %T(%v) expected Channel", val, val)
- }
- if c.Buffer == 0 {
- return fmt.Errorf("got buffer address %d expected nonzero", c.Buffer)
- }
- if c.Length != 0 {
- return fmt.Errorf("got length %d expected 0", c.Length)
- }
- if c.Capacity != 0 {
- return fmt.Errorf("got capacity %d expected 0", c.Capacity)
- }
- return nil
- })
-
- checkValue("main.Z_channel_2", func(val debug.Value) error {
- c, ok := val.(debug.Channel)
- if !ok {
- return fmt.Errorf("got %T(%v) expected Channel", val, val)
- }
- if c.Buffer == 0 {
- return fmt.Errorf("got buffer address %d expected nonzero", c.Buffer)
- }
- if c.Length != 0 {
- return fmt.Errorf("got length %d expected 0", c.Length)
- }
- if c.Capacity != 0 {
- return fmt.Errorf("got capacity %d expected 0", c.Capacity)
- }
- return nil
- })
-
- checkValue("main.Z_channel_nil", func(val debug.Value) error {
- c, ok := val.(debug.Channel)
- if !ok {
- return fmt.Errorf("got %T(%v) expected Channel", val, val)
- }
- if c.Buffer != 0 {
- return fmt.Errorf("got buffer address %d expected 0", c.Buffer)
- }
- if c.Length != 0 {
- return fmt.Errorf("got length %d expected 0", c.Length)
- }
- if c.Capacity != 0 {
- return fmt.Errorf("got capacity %d expected 0", c.Capacity)
- }
- return nil
- })
-
- checkValue("main.Z_channel_buffered", func(val debug.Value) error {
- c, ok := val.(debug.Channel)
- if !ok {
- return fmt.Errorf("got %T(%v) expected Channel", val, val)
- }
- if c.Buffer == 0 {
- return fmt.Errorf("got buffer address %d expected nonzero", c.Buffer)
- }
- if c.Length != 6 {
- return fmt.Errorf("got length %d expected 6", c.Length)
- }
- if c.Capacity != 10 {
- return fmt.Errorf("got capacity %d expected 10", c.Capacity)
- }
- if c.Stride != 2 {
- return fmt.Errorf("got stride %d expected 2", c.Stride)
- }
- expected := []int16{8, 9, 10, 11, 12, 13}
- for i := uint64(0); i < 6; i++ {
- if v, err := prog.Value(c.Element(i)); err != nil {
- return fmt.Errorf("reading element %d: %s", i, err)
- } else if v != expected[i] {
- return fmt.Errorf("element %d: got %T(%v) want %T(%d)", i, v, v, expected[i], expected[i])
- }
- }
- v := c.Element(6)
- if v.Address != 0 {
- return fmt.Errorf("invalid element returned Var with address %d, expected 0", v.Address)
- }
- return nil
- })
-
- checkValue("main.Z_func_bar", func(val debug.Value) error {
- f, ok := val.(debug.Func)
- if !ok {
- return fmt.Errorf("got %T(%v) expected Func", val, val)
- }
- if f.Address == 0 {
- return fmt.Errorf("got func address %d expected nonzero", f.Address)
- }
- return nil
- })
-
- checkValue("main.Z_func_nil", func(val debug.Value) error {
- f, ok := val.(debug.Func)
- if !ok {
- return fmt.Errorf("got %T(%v) expected Func", val, val)
- }
- if f.Address != 0 {
- return fmt.Errorf("got func address %d expected zero", f.Address)
- }
- return nil
- })
- }
|