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