| // Copyright 2014 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // Demo program that starts another program and calls Ogle library functions |
| // to debug it. |
| |
| package ogler |
| |
| import ( |
| "fmt" |
| "log" |
| "os" |
| "os/exec" |
| "testing" |
| |
| "golang.org/x/debug/ogle/program/client" |
| ) |
| |
| var expected_vars = 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 int 0xX)`, |
| `main.Z_channel_buffered`: `(chan int 0xX [0/10])`, |
| `main.Z_channel_nil`: `(chan int <nil>)`, |
| `main.Z_array_of_empties`: `[2]struct struct {}{struct struct {} {}, (struct struct {} 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_int`: `-21`, |
| `main.Z_int16`: `-32321`, |
| `main.Z_int32`: `-1987654321`, |
| `main.Z_int64`: `-9012345678987654321`, |
| `main.Z_int8`: `-121`, |
| `main.Z_interface`: `("*main.FooStruct", 0xX)`, |
| `main.Z_interface_nil`: `(<nil>, <nil>)`, |
| `main.Z_interface_typed_nil`: `("*main.FooStruct", <nil>)`, |
| `main.Z_map`: `{-21:3.54321}`, |
| `main.Z_map_2`: `{1024:1}`, |
| `main.Z_map_empty`: `{}`, |
| `main.Z_map_nil`: `<nil>`, |
| `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`: `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`, |
| } |
| |
| 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 |
| } |
| } |
| |
| // 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 { |
| 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) |
| } |
| |
| func run(t *testing.T, name string, args ...string) { |
| cmd := exec.Command(name, args...) |
| cmd.Stdout = os.Stdout |
| cmd.Stderr = os.Stderr |
| err := cmd.Run() |
| if err != nil { |
| t.Fatal(err) |
| } |
| } |
| |
| const ( |
| proxySrc = "golang.org/x/debug/ogle/cmd/ogleproxy" |
| proxyBinary = "./ogleproxy" |
| traceeSrc = "golang.org/x/debug/ogle/demo/tracee" |
| traceeBinary = "./tracee" |
| ) |
| |
| func TestBreakAndEval(t *testing.T) { |
| run(t, "go", "build", "-o", proxyBinary, proxySrc) |
| defer os.Remove(proxyBinary) |
| |
| run(t, "go", "build", "-o", traceeBinary, traceeSrc) |
| defer os.Remove(traceeBinary) |
| |
| client.OgleproxyCmd = proxyBinary |
| prog, err := client.Run("localhost", traceeBinary) |
| if err != nil { |
| log.Fatalf("Run: %v", err) |
| } |
| |
| _, err = prog.Run() |
| if err != nil { |
| log.Fatalf("Run: %v", err) |
| } |
| |
| pcs, err := prog.Breakpoint("re:main.foo") |
| if err != nil { |
| log.Fatalf("Breakpoint: %v", err) |
| } |
| fmt.Printf("breakpoints set at %x\n", pcs) |
| |
| _, err = prog.Resume() |
| if err != nil { |
| log.Fatalf("Resume: %v", err) |
| } |
| |
| frames, err := prog.Frames(100) |
| if err != nil { |
| log.Fatalf("prog.Frames error: %v", err) |
| } |
| fmt.Printf("%#v\n", frames) |
| |
| 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 |
| // expected_vars. |
| 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 := expected_vars[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 expected_vars { |
| if !seen[v] { |
| log.Fatalf("Didn't get %s = %s\n", v, e) |
| } |
| } |
| } |