Left: | ||
Right: |
OLD | NEW |
---|---|
1 // Copyright 2014 The Go Authors. All rights reserved. | 1 // Copyright 2014 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 // Package server provides RPC access to a local program being debugged. | 5 // Package server provides RPC access to a local program being debugged. |
6 // It is the remote end of the client implementation of the Program interface. | 6 // It is the remote end of the client implementation of the Program interface. |
7 package server | 7 package server |
8 | 8 |
9 import ( | 9 import ( |
10 "encoding/binary" | |
11 "fmt" | 10 "fmt" |
12 "os" | 11 "os" |
13 "regexp" | 12 "regexp" |
14 "strconv" | 13 "strconv" |
15 "strings" | 14 "strings" |
16 "sync" | 15 "sync" |
17 "syscall" | 16 "syscall" |
18 | 17 |
19 "code.google.com/p/ogle/debug/dwarf" | 18 "code.google.com/p/ogle/debug/dwarf" |
20 "code.google.com/p/ogle/debug/elf" | 19 "code.google.com/p/ogle/debug/elf" |
21 "code.google.com/p/ogle/debug/macho" | 20 "code.google.com/p/ogle/debug/macho" |
22 | 21 |
22 "code.google.com/p/ogle/arch" | |
23 "code.google.com/p/ogle/program" | 23 "code.google.com/p/ogle/program" |
24 "code.google.com/p/ogle/program/proxyrpc" | 24 "code.google.com/p/ogle/program/proxyrpc" |
25 ) | 25 ) |
26 | 26 |
27 type breakpoint struct { | 27 type breakpoint struct { |
28 pc uint64 | 28 pc uint64 |
29 » origInstr byte // TODO: don't be amd64-specific. | 29 » origInstr [arch.MaxBreakpointSize]byte |
30 } | 30 } |
31 | 31 |
32 type Server struct { | 32 type Server struct { |
33 arch arch.Architecture | |
33 executable string // Name of executable. | 34 executable string // Name of executable. |
34 dwarfData *dwarf.Data | 35 dwarfData *dwarf.Data |
35 | 36 |
36 mu sync.Mutex | 37 mu sync.Mutex |
37 | 38 |
38 fc chan func() error | 39 fc chan func() error |
39 ec chan error | 40 ec chan error |
40 | 41 |
41 proc *os.Process | 42 proc *os.Process |
42 breakpoints map[uint64]breakpoint | 43 breakpoints map[uint64]breakpoint |
43 files []*file // Index == file descriptor. | 44 files []*file // Index == file descriptor. |
44 } | 45 } |
45 | 46 |
46 // New parses the executable and builds local data structures for answering requ ests. | 47 // New parses the executable and builds local data structures for answering requ ests. |
47 // It returns a Server ready to serve requests about the executable. | 48 // It returns a Server ready to serve requests about the executable. |
48 func New(executable string) (*Server, error) { | 49 func New(executable string) (*Server, error) { |
49 fd, err := os.Open(executable) | 50 fd, err := os.Open(executable) |
50 if err != nil { | 51 if err != nil { |
51 return nil, err | 52 return nil, err |
52 } | 53 } |
53 defer fd.Close() | 54 defer fd.Close() |
54 dwarfData, err := loadDwarfData(fd) | 55 dwarfData, err := loadDwarfData(fd) |
55 if err != nil { | 56 if err != nil { |
56 return nil, err | 57 return nil, err |
57 } | 58 } |
58 srv := &Server{ | 59 srv := &Server{ |
60 arch: arch.AMD64, // TODO: How do we discover this? | |
59 executable: executable, | 61 executable: executable, |
60 dwarfData: dwarfData, | 62 dwarfData: dwarfData, |
61 fc: make(chan func() error), | 63 fc: make(chan func() error), |
62 ec: make(chan error), | 64 ec: make(chan error), |
63 breakpoints: make(map[uint64]breakpoint), | 65 breakpoints: make(map[uint64]breakpoint), |
64 } | 66 } |
65 go ptraceRun(srv.fc, srv.ec) | 67 go ptraceRun(srv.fc, srv.ec) |
66 return srv, nil | 68 return srv, nil |
67 } | 69 } |
68 | 70 |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
211 err = s.liftBreakpoints() | 213 err = s.liftBreakpoints() |
212 if err != nil { | 214 if err != nil { |
213 return err | 215 return err |
214 } | 216 } |
215 | 217 |
216 err = s.ptraceGetRegs(s.proc.Pid, ®s) | 218 err = s.ptraceGetRegs(s.proc.Pid, ®s) |
217 if err != nil { | 219 if err != nil { |
218 return err | 220 return err |
219 } | 221 } |
220 | 222 |
221 » regs.Rip-- // TODO: depends on length of trap. | 223 » regs.Rip -= uint64(s.arch.BreakpointSize) |
222 err = s.ptraceSetRegs(s.proc.Pid, ®s) | 224 err = s.ptraceSetRegs(s.proc.Pid, ®s) |
223 if err != nil { | 225 if err != nil { |
224 return fmt.Errorf("ptraceSetRegs: %v", err) | 226 return fmt.Errorf("ptraceSetRegs: %v", err) |
225 } | 227 } |
226 | 228 |
227 resp.Status.PC = regs.Rip | 229 resp.Status.PC = regs.Rip |
228 resp.Status.SP = regs.Rsp | 230 resp.Status.SP = regs.Rsp |
229 return nil | 231 return nil |
230 } | 232 } |
231 | 233 |
232 func (s *Server) Breakpoint(req *proxyrpc.BreakpointRequest, resp *proxyrpc.Brea kpointResponse) (err error) { | 234 func (s *Server) Breakpoint(req *proxyrpc.BreakpointRequest, resp *proxyrpc.Brea kpointResponse) (err error) { |
233 s.mu.Lock() | 235 s.mu.Lock() |
234 defer s.mu.Unlock() | 236 defer s.mu.Unlock() |
235 | 237 |
236 addrs, err := s.eval(req.Address) | 238 addrs, err := s.eval(req.Address) |
237 if err != nil { | 239 if err != nil { |
238 return err | 240 return err |
239 } | 241 } |
242 var bp breakpoint | |
240 for _, addr := range addrs { | 243 for _, addr := range addrs { |
241 pc, err := s.evalAddress(addr) | 244 pc, err := s.evalAddress(addr) |
242 if err != nil { | 245 if err != nil { |
243 return err | 246 return err |
244 } | 247 } |
245 if _, alreadySet := s.breakpoints[pc]; alreadySet { | 248 if _, alreadySet := s.breakpoints[pc]; alreadySet { |
246 return fmt.Errorf("breakpoint already set at %#x (TODO)" , pc) | 249 return fmt.Errorf("breakpoint already set at %#x (TODO)" , pc) |
247 } | 250 } |
248 | 251 |
249 » » var buf [1]byte | 252 » » err = s.ptracePeek(s.proc.Pid, uintptr(pc), bp.origInstr[:s.arch .BreakpointSize]) |
250 » » err = s.ptracePeek(s.proc.Pid, uintptr(pc), buf[:]) | |
251 if err != nil { | 253 if err != nil { |
252 » » » return fmt.Errorf("ptracePoke: %v", err) | 254 » » » return fmt.Errorf("ptracePeek: %v", err) |
253 } | 255 } |
254 » » s.breakpoints[pc] = breakpoint{pc: pc, origInstr: buf[0]} | 256 » » bp.pc = pc |
257 » » s.breakpoints[pc] = bp | |
255 } | 258 } |
256 | 259 |
257 return nil | 260 return nil |
258 } | 261 } |
259 | 262 |
260 func (s *Server) setBreakpoints() error { | 263 func (s *Server) setBreakpoints() error { |
261 var buf [1]byte | |
262 buf[0] = 0xcc // INT 3 instruction on x86. | |
263 for pc := range s.breakpoints { | 264 for pc := range s.breakpoints { |
264 » » err := s.ptracePoke(s.proc.Pid, uintptr(pc), buf[:]) | 265 » » err := s.ptracePoke(s.proc.Pid, uintptr(pc), s.arch.BreakpointIn str[:]) |
nigeltao
2014/04/09 05:23:49
Drop the "[:]".
| |
265 if err != nil { | 266 if err != nil { |
266 return fmt.Errorf("setBreakpoints: %v", err) | 267 return fmt.Errorf("setBreakpoints: %v", err) |
267 } | 268 } |
268 } | 269 } |
269 return nil | 270 return nil |
270 } | 271 } |
271 | 272 |
272 func (s *Server) liftBreakpoints() error { | 273 func (s *Server) liftBreakpoints() error { |
273 var buf [1]byte | |
274 for pc, breakpoint := range s.breakpoints { | 274 for pc, breakpoint := range s.breakpoints { |
275 » » buf[0] = breakpoint.origInstr | 275 » » err := s.ptracePoke(s.proc.Pid, uintptr(pc), breakpoint.origInst r[:]) |
nigeltao
2014/04/09 05:23:49
breakpoint.origInstr[:s.arch.BreakpointSize]
| |
276 » » err := s.ptracePoke(s.proc.Pid, uintptr(pc), buf[:]) | |
277 if err != nil { | 276 if err != nil { |
278 return fmt.Errorf("liftBreakpoints: %v", err) | 277 return fmt.Errorf("liftBreakpoints: %v", err) |
279 } | 278 } |
280 } | 279 } |
281 return nil | 280 return nil |
282 } | 281 } |
283 | 282 |
284 func (s *Server) Eval(req *proxyrpc.EvalRequest, resp *proxyrpc.EvalResponse) (e rr error) { | 283 func (s *Server) Eval(req *proxyrpc.EvalRequest, resp *proxyrpc.EvalResponse) (e rr error) { |
285 s.mu.Lock() | 284 s.mu.Lock() |
286 defer s.mu.Unlock() | 285 defer s.mu.Unlock() |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
353 return fmt.Errorf("Frames.Count != 1 is not implemented") | 352 return fmt.Errorf("Frames.Count != 1 is not implemented") |
354 } | 353 } |
355 | 354 |
356 // TODO: we're assuming we're at a function's entry point (LowPC). | 355 // TODO: we're assuming we're at a function's entry point (LowPC). |
357 | 356 |
358 regs := syscall.PtraceRegs{} | 357 regs := syscall.PtraceRegs{} |
359 err := s.ptraceGetRegs(s.proc.Pid, ®s) | 358 err := s.ptraceGetRegs(s.proc.Pid, ®s) |
360 if err != nil { | 359 if err != nil { |
361 return err | 360 return err |
362 } | 361 } |
363 » fp := regs.Rsp + 8 // TODO: 8 for the return address is amd64 specific. | 362 » fp := regs.Rsp + uint64(s.arch.PointerSize) |
364 | 363 |
365 entry, err := s.entryForPC(regs.Rip) | 364 entry, err := s.entryForPC(regs.Rip) |
366 if err != nil { | 365 if err != nil { |
367 return err | 366 return err |
368 } | 367 } |
369 | 368 |
370 var buf [8]byte | 369 var buf [8]byte |
371 frame := program.Frame{} | 370 frame := program.Frame{} |
372 r := s.dwarfData.Reader() | 371 r := s.dwarfData.Reader() |
373 r.Seek(entry.Offset) | 372 r.Seek(entry.Offset) |
(...skipping 20 matching lines...) Expand all Loading... | |
394 offset := evalLocation(f.Val.([]uint8)) | 393 offset := evalLocation(f.Val.([]uint8)) |
395 location = uintptr(int64(fp) + offset) | 394 location = uintptr(int64(fp) + offset) |
396 frame.S += fmt.Sprintf("(%d(FP))", offset) | 395 frame.S += fmt.Sprintf("(%d(FP))", offset) |
397 case dwarf.AttrName: | 396 case dwarf.AttrName: |
398 frame.S += " " + f.Val.(string) | 397 frame.S += " " + f.Val.(string) |
399 case dwarf.AttrType: | 398 case dwarf.AttrType: |
400 t, err := s.dwarfData.Type(f.Val.(dwarf.Offset)) | 399 t, err := s.dwarfData.Type(f.Val.(dwarf.Offset)) |
401 if err == nil { | 400 if err == nil { |
402 frame.S += fmt.Sprintf("[%v]", t) | 401 frame.S += fmt.Sprintf("[%v]", t) |
403 } | 402 } |
404 » » » » // TODO: don't assume amd64. | 403 » » » » if t.String() != "int" || t.Size() != int64(s.ar ch.IntSize) { |
405 » » » » if t.String() != "int" && t.Size() == 8 { | |
406 break | 404 break |
407 } | 405 } |
408 if location == 0 { | 406 if location == 0 { |
409 return fmt.Errorf("no location for Forma lParameter") | 407 return fmt.Errorf("no location for Forma lParameter") |
410 } | 408 } |
411 » » » » err = s.ptracePeek(s.proc.Pid, location, buf[:8] ) | 409 » » » » err = s.ptracePeek(s.proc.Pid, location, buf[:s. arch.IntSize]) |
412 if err != nil { | 410 if err != nil { |
413 return err | 411 return err |
414 } | 412 } |
415 » » » » // TODO: don't assume little-endian. | 413 » » » » frame.S += fmt.Sprintf("==%#x", s.arch.Int(buf[: s.arch.IntSize])) |
416 » » » » frame.S += fmt.Sprintf("==%#x", binary.LittleEnd ian.Uint64(buf[:8])) | |
417 } | 414 } |
418 } | 415 } |
419 } | 416 } |
420 resp.Frames = append(resp.Frames, frame) | 417 resp.Frames = append(resp.Frames, frame) |
421 return nil | 418 return nil |
422 } | 419 } |
OLD | NEW |