1// Copyright 2019 Google LLC 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// +build linux 16 17// Package local provides access to a local program. 18package local 19 20import ( 21 "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug" 22 "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/server" 23 "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/server/protocol" 24) 25 26var _ debug.Program = (*Program)(nil) 27var _ debug.File = (*File)(nil) 28 29// Program implements the debug.Program interface. 30// Through that interface it provides access to a program being debugged. 31type Program struct { 32 s *server.Server 33} 34 35// New creates a new program from the specified file. 36// The program can then be started by the Run method. 37func New(textFile string) (*Program, error) { 38 s, err := server.New(textFile) 39 return &Program{s: s}, err 40} 41 42func (p *Program) Open(name string, mode string) (debug.File, error) { 43 req := protocol.OpenRequest{ 44 Name: name, 45 Mode: mode, 46 } 47 var resp protocol.OpenResponse 48 err := p.s.Open(&req, &resp) 49 if err != nil { 50 return nil, err 51 } 52 f := &File{ 53 prog: p, 54 fd: resp.FD, 55 } 56 return f, nil 57} 58 59func (p *Program) Run(args ...string) (debug.Status, error) { 60 req := protocol.RunRequest{args} 61 var resp protocol.RunResponse 62 err := p.s.Run(&req, &resp) 63 if err != nil { 64 return debug.Status{}, err 65 } 66 return resp.Status, nil 67} 68 69func (p *Program) Stop() (debug.Status, error) { 70 panic("unimplemented") 71} 72 73func (p *Program) Resume() (debug.Status, error) { 74 req := protocol.ResumeRequest{} 75 var resp protocol.ResumeResponse 76 err := p.s.Resume(&req, &resp) 77 if err != nil { 78 return debug.Status{}, err 79 } 80 return resp.Status, nil 81} 82 83func (p *Program) Kill() (debug.Status, error) { 84 panic("unimplemented") 85} 86 87func (p *Program) Breakpoint(address uint64) ([]uint64, error) { 88 req := protocol.BreakpointRequest{ 89 Address: address, 90 } 91 var resp protocol.BreakpointResponse 92 err := p.s.Breakpoint(&req, &resp) 93 return resp.PCs, err 94} 95 96func (p *Program) BreakpointAtFunction(name string) ([]uint64, error) { 97 req := protocol.BreakpointAtFunctionRequest{ 98 Function: name, 99 } 100 var resp protocol.BreakpointResponse 101 err := p.s.BreakpointAtFunction(&req, &resp) 102 return resp.PCs, err 103} 104 105func (p *Program) BreakpointAtLine(file string, line uint64) ([]uint64, error) { 106 req := protocol.BreakpointAtLineRequest{ 107 File: file, 108 Line: line, 109 } 110 var resp protocol.BreakpointResponse 111 err := p.s.BreakpointAtLine(&req, &resp) 112 return resp.PCs, err 113} 114 115func (p *Program) DeleteBreakpoints(pcs []uint64) error { 116 req := protocol.DeleteBreakpointsRequest{PCs: pcs} 117 var resp protocol.DeleteBreakpointsResponse 118 return p.s.DeleteBreakpoints(&req, &resp) 119} 120 121func (p *Program) Eval(expr string) ([]string, error) { 122 req := protocol.EvalRequest{ 123 Expr: expr, 124 } 125 var resp protocol.EvalResponse 126 err := p.s.Eval(&req, &resp) 127 return resp.Result, err 128} 129 130func (p *Program) Evaluate(e string) (debug.Value, error) { 131 req := protocol.EvaluateRequest{ 132 Expression: e, 133 } 134 var resp protocol.EvaluateResponse 135 err := p.s.Evaluate(&req, &resp) 136 return resp.Result, err 137} 138 139func (p *Program) Frames(count int) ([]debug.Frame, error) { 140 req := protocol.FramesRequest{ 141 Count: count, 142 } 143 var resp protocol.FramesResponse 144 err := p.s.Frames(&req, &resp) 145 return resp.Frames, err 146} 147 148func (p *Program) Goroutines() ([]*debug.Goroutine, error) { 149 req := protocol.GoroutinesRequest{} 150 var resp protocol.GoroutinesResponse 151 err := p.s.Goroutines(&req, &resp) 152 return resp.Goroutines, err 153} 154 155func (p *Program) VarByName(name string) (debug.Var, error) { 156 req := protocol.VarByNameRequest{Name: name} 157 var resp protocol.VarByNameResponse 158 err := p.s.VarByName(&req, &resp) 159 return resp.Var, err 160} 161 162func (p *Program) Value(v debug.Var) (debug.Value, error) { 163 req := protocol.ValueRequest{Var: v} 164 var resp protocol.ValueResponse 165 err := p.s.Value(&req, &resp) 166 return resp.Value, err 167} 168 169func (p *Program) MapElement(m debug.Map, index uint64) (debug.Var, debug.Var, error) { 170 req := protocol.MapElementRequest{Map: m, Index: index} 171 var resp protocol.MapElementResponse 172 err := p.s.MapElement(&req, &resp) 173 return resp.Key, resp.Value, err 174} 175 176// File implements the debug.File interface, providing access 177// to file-like resources associated with the target program. 178type File struct { 179 prog *Program // The Program associated with the file. 180 fd int // File descriptor. 181} 182 183func (f *File) ReadAt(p []byte, offset int64) (int, error) { 184 req := protocol.ReadAtRequest{ 185 FD: f.fd, 186 Len: len(p), 187 Offset: offset, 188 } 189 var resp protocol.ReadAtResponse 190 err := f.prog.s.ReadAt(&req, &resp) 191 return copy(p, resp.Data), err 192} 193 194func (f *File) WriteAt(p []byte, offset int64) (int, error) { 195 panic("unimplemented") 196} 197 198func (f *File) Close() error { 199 req := protocol.CloseRequest{ 200 FD: f.fd, 201 } 202 var resp protocol.CloseResponse 203 err := f.prog.s.Close(&req, &resp) 204 return err 205} 206