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 server provides RPC access to a local program being debugged. 18// It is the remote end of the client implementation of the Program interface. 19package server 20 21//go:generate sh -c "m4 -P eval.m4 > eval.go" 22 23import ( 24 "bytes" 25 "errors" 26 "fmt" 27 "os" 28 "regexp" 29 "strconv" 30 "strings" 31 "sync" 32 "syscall" 33 34 "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug" 35 "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/arch" 36 "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf" 37 "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf" 38 "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/server/protocol" 39) 40 41type breakpoint struct { 42 pc uint64 43 origInstr [arch.MaxBreakpointSize]byte 44} 45 46type call struct { 47 req, resp interface{} 48 errc chan error 49} 50 51type Server struct { 52 arch arch.Architecture 53 executable string // Name of executable. 54 dwarfData *dwarf.Data 55 56 breakpointc chan call 57 otherc chan call 58 59 fc chan func() error 60 ec chan error 61 62 proc *os.Process 63 procIsUp bool 64 stoppedPid int 65 stoppedRegs syscall.PtraceRegs 66 topOfStackAddrs []uint64 67 breakpoints map[uint64]breakpoint 68 files []*file // Index == file descriptor. 69 printer *Printer 70 71 // goroutineStack reads the stack of a (non-running) goroutine. 72 goroutineStack func(uint64) ([]debug.Frame, error) 73 goroutineStackOnce sync.Once 74} 75 76// peek implements the Peeker interface required by the printer. 77func (s *Server) peek(offset uintptr, buf []byte) error { 78 return s.ptracePeek(s.stoppedPid, offset, buf) 79} 80 81// New parses the executable and builds local data structures for answering requests. 82// It returns a Server ready to serve requests about the executable. 83func New(executable string) (*Server, error) { 84 fd, err := os.Open(executable) 85 if err != nil { 86 return nil, err 87 } 88 defer fd.Close() 89 architecture, dwarfData, err := loadExecutable(fd) 90 if err != nil { 91 return nil, err 92 } 93 srv := &Server{ 94 arch: *architecture, 95 executable: executable, 96 dwarfData: dwarfData, 97 breakpointc: make(chan call), 98 otherc: make(chan call), 99 fc: make(chan func() error), 100 ec: make(chan error), 101 breakpoints: make(map[uint64]breakpoint), 102 } 103 srv.printer = NewPrinter(architecture, dwarfData, srv) 104 go ptraceRun(srv.fc, srv.ec) 105 go srv.loop() 106 return srv, nil 107} 108 109func loadExecutable(f *os.File) (*arch.Architecture, *dwarf.Data, error) { 110 // TODO: How do we detect NaCl? 111 if obj, err := elf.NewFile(f); err == nil { 112 dwarfData, err := obj.DWARF() 113 if err != nil { 114 return nil, nil, err 115 } 116 117 switch obj.Machine { 118 case elf.EM_ARM: 119 return &arch.ARM, dwarfData, nil 120 case elf.EM_386: 121 switch obj.Class { 122 case elf.ELFCLASS32: 123 return &arch.X86, dwarfData, nil 124 case elf.ELFCLASS64: 125 return &arch.AMD64, dwarfData, nil 126 } 127 case elf.EM_X86_64: 128 return &arch.AMD64, dwarfData, nil 129 } 130 return nil, nil, fmt.Errorf("unrecognized ELF architecture") 131 } 132 return nil, nil, fmt.Errorf("unrecognized binary format") 133} 134 135func (s *Server) loop() { 136 for { 137 var c call 138 select { 139 case c = <-s.breakpointc: 140 case c = <-s.otherc: 141 } 142 s.dispatch(c) 143 } 144} 145 146func (s *Server) dispatch(c call) { 147 switch req := c.req.(type) { 148 case *protocol.BreakpointRequest: 149 c.errc <- s.handleBreakpoint(req, c.resp.(*protocol.BreakpointResponse)) 150 case *protocol.BreakpointAtFunctionRequest: 151 c.errc <- s.handleBreakpointAtFunction(req, c.resp.(*protocol.BreakpointResponse)) 152 case *protocol.BreakpointAtLineRequest: 153 c.errc <- s.handleBreakpointAtLine(req, c.resp.(*protocol.BreakpointResponse)) 154 case *protocol.DeleteBreakpointsRequest: 155 c.errc <- s.handleDeleteBreakpoints(req, c.resp.(*protocol.DeleteBreakpointsResponse)) 156 case *protocol.CloseRequest: 157 c.errc <- s.handleClose(req, c.resp.(*protocol.CloseResponse)) 158 case *protocol.EvalRequest: 159 c.errc <- s.handleEval(req, c.resp.(*protocol.EvalResponse)) 160 case *protocol.EvaluateRequest: 161 c.errc <- s.handleEvaluate(req, c.resp.(*protocol.EvaluateResponse)) 162 case *protocol.FramesRequest: 163 c.errc <- s.handleFrames(req, c.resp.(*protocol.FramesResponse)) 164 case *protocol.OpenRequest: 165 c.errc <- s.handleOpen(req, c.resp.(*protocol.OpenResponse)) 166 case *protocol.ReadAtRequest: 167 c.errc <- s.handleReadAt(req, c.resp.(*protocol.ReadAtResponse)) 168 case *protocol.ResumeRequest: 169 c.errc <- s.handleResume(req, c.resp.(*protocol.ResumeResponse)) 170 case *protocol.RunRequest: 171 c.errc <- s.handleRun(req, c.resp.(*protocol.RunResponse)) 172 case *protocol.VarByNameRequest: 173 c.errc <- s.handleVarByName(req, c.resp.(*protocol.VarByNameResponse)) 174 case *protocol.ValueRequest: 175 c.errc <- s.handleValue(req, c.resp.(*protocol.ValueResponse)) 176 case *protocol.MapElementRequest: 177 c.errc <- s.handleMapElement(req, c.resp.(*protocol.MapElementResponse)) 178 case *protocol.GoroutinesRequest: 179 c.errc <- s.handleGoroutines(req, c.resp.(*protocol.GoroutinesResponse)) 180 default: 181 panic(fmt.Sprintf("unexpected call request type %T", c.req)) 182 } 183} 184 185func (s *Server) call(c chan call, req, resp interface{}) error { 186 errc := make(chan error) 187 c <- call{req, resp, errc} 188 return <-errc 189} 190 191type file struct { 192 mode string 193 index int 194 f debug.File 195} 196 197func (s *Server) Open(req *protocol.OpenRequest, resp *protocol.OpenResponse) error { 198 return s.call(s.otherc, req, resp) 199} 200 201func (s *Server) handleOpen(req *protocol.OpenRequest, resp *protocol.OpenResponse) error { 202 // TODO: Better simulation. For now we just open the named OS file. 203 var flag int 204 switch req.Mode { 205 case "r": 206 flag = os.O_RDONLY 207 case "w": 208 flag = os.O_WRONLY 209 case "rw": 210 flag = os.O_RDWR 211 default: 212 return fmt.Errorf("Open: bad open mode %q", req.Mode) 213 } 214 osFile, err := os.OpenFile(req.Name, flag, 0) 215 if err != nil { 216 return err 217 } 218 // Find a file descriptor (index) slot. 219 index := 0 220 for ; index < len(s.files) && s.files[index] != nil; index++ { 221 } 222 f := &file{ 223 mode: req.Mode, 224 index: index, 225 f: osFile, 226 } 227 if index == len(s.files) { 228 s.files = append(s.files, f) 229 } else { 230 s.files[index] = f 231 } 232 return nil 233} 234 235func (s *Server) ReadAt(req *protocol.ReadAtRequest, resp *protocol.ReadAtResponse) error { 236 return s.call(s.otherc, req, resp) 237} 238 239func (s *Server) handleReadAt(req *protocol.ReadAtRequest, resp *protocol.ReadAtResponse) error { 240 fd := req.FD 241 if fd < 0 || len(s.files) <= fd || s.files[fd] == nil { 242 return fmt.Errorf("ReadAt: bad file descriptor %d", fd) 243 } 244 f := s.files[fd] 245 buf := make([]byte, req.Len) // TODO: Don't allocate every time 246 n, err := f.f.ReadAt(buf, req.Offset) 247 resp.Data = buf[:n] 248 return err 249} 250 251func (s *Server) Close(req *protocol.CloseRequest, resp *protocol.CloseResponse) error { 252 return s.call(s.otherc, req, resp) 253} 254 255func (s *Server) handleClose(req *protocol.CloseRequest, resp *protocol.CloseResponse) error { 256 fd := req.FD 257 if fd < 0 || fd >= len(s.files) || s.files[fd] == nil { 258 return fmt.Errorf("Close: bad file descriptor %d", fd) 259 } 260 err := s.files[fd].f.Close() 261 // Remove it regardless 262 s.files[fd] = nil 263 return err 264} 265 266func (s *Server) Run(req *protocol.RunRequest, resp *protocol.RunResponse) error { 267 return s.call(s.otherc, req, resp) 268} 269 270func (s *Server) handleRun(req *protocol.RunRequest, resp *protocol.RunResponse) error { 271 if s.proc != nil { 272 s.proc.Kill() 273 s.proc = nil 274 s.procIsUp = false 275 s.stoppedPid = 0 276 s.stoppedRegs = syscall.PtraceRegs{} 277 s.topOfStackAddrs = nil 278 } 279 argv := append([]string{s.executable}, req.Args...) 280 p, err := s.startProcess(s.executable, argv, &os.ProcAttr{ 281 Files: []*os.File{ 282 nil, // TODO: be able to feed the target's stdin. 283 os.Stderr, // TODO: be able to capture the target's stdout. 284 os.Stderr, 285 }, 286 Sys: &syscall.SysProcAttr{ 287 Pdeathsig: syscall.SIGKILL, 288 Ptrace: true, 289 }, 290 }) 291 if err != nil { 292 return err 293 } 294 s.proc = p 295 s.stoppedPid = p.Pid 296 return nil 297} 298 299func (s *Server) Resume(req *protocol.ResumeRequest, resp *protocol.ResumeResponse) error { 300 return s.call(s.otherc, req, resp) 301} 302 303func (s *Server) handleResume(req *protocol.ResumeRequest, resp *protocol.ResumeResponse) error { 304 if s.proc == nil { 305 return fmt.Errorf("Resume: Run did not successfully start a process") 306 } 307 308 if !s.procIsUp { 309 s.procIsUp = true 310 if _, err := s.waitForTrap(s.stoppedPid, false); err != nil { 311 return err 312 } 313 if err := s.ptraceSetOptions(s.stoppedPid, syscall.PTRACE_O_TRACECLONE); err != nil { 314 return fmt.Errorf("ptraceSetOptions: %v", err) 315 } 316 } else if _, ok := s.breakpoints[s.stoppedRegs.Rip]; ok { 317 if err := s.ptraceSingleStep(s.stoppedPid); err != nil { 318 return fmt.Errorf("ptraceSingleStep: %v", err) 319 } 320 if _, err := s.waitForTrap(s.stoppedPid, false); err != nil { 321 return err 322 } 323 } 324 325 for { 326 if err := s.setBreakpoints(); err != nil { 327 return err 328 } 329 if err := s.ptraceCont(s.stoppedPid, 0); err != nil { 330 return fmt.Errorf("ptraceCont: %v", err) 331 } 332 333 wpid, err := s.waitForTrap(-1, true) 334 if err == nil { 335 s.stoppedPid = wpid 336 break 337 } 338 bce, ok := err.(*breakpointsChangedError) 339 if !ok { 340 return err 341 } 342 343 if err := syscall.Kill(s.stoppedPid, syscall.SIGSTOP); err != nil { 344 return fmt.Errorf("kill(SIGSTOP): %v", err) 345 } 346 _, status, err := s.wait(s.stoppedPid, false) 347 if err != nil { 348 return fmt.Errorf("wait (after SIGSTOP): %v", err) 349 } 350 if !status.Stopped() || status.StopSignal() != syscall.SIGSTOP { 351 return fmt.Errorf("wait (after SIGSTOP): unexpected wait status 0x%x", status) 352 } 353 354 if err := s.liftBreakpoints(); err != nil { 355 return err 356 } 357 358 loop: 359 for c := bce.call; ; { 360 s.dispatch(c) 361 select { 362 case c = <-s.breakpointc: 363 default: 364 break loop 365 } 366 } 367 } 368 if err := s.liftBreakpoints(); err != nil { 369 return err 370 } 371 372 if err := s.ptraceGetRegs(s.stoppedPid, &s.stoppedRegs); err != nil { 373 return fmt.Errorf("ptraceGetRegs: %v", err) 374 } 375 376 s.stoppedRegs.Rip -= uint64(s.arch.BreakpointSize) 377 378 if err := s.ptraceSetRegs(s.stoppedPid, &s.stoppedRegs); err != nil { 379 return fmt.Errorf("ptraceSetRegs: %v", err) 380 } 381 382 resp.Status.PC = s.stoppedRegs.Rip 383 resp.Status.SP = s.stoppedRegs.Rsp 384 return nil 385} 386 387func (s *Server) waitForTrap(pid int, allowBreakpointsChange bool) (wpid int, err error) { 388 for { 389 wpid, status, err := s.wait(pid, allowBreakpointsChange) 390 if err != nil { 391 if _, ok := err.(*breakpointsChangedError); !ok { 392 err = fmt.Errorf("wait: %v", err) 393 } 394 return 0, err 395 } 396 if status.StopSignal() == syscall.SIGTRAP && status.TrapCause() != syscall.PTRACE_EVENT_CLONE { 397 return wpid, nil 398 } 399 if status.StopSignal() == syscall.SIGPROF { 400 err = s.ptraceCont(wpid, int(syscall.SIGPROF)) 401 } else { 402 err = s.ptraceCont(wpid, 0) // TODO: non-zero when wait catches other signals? 403 } 404 if err != nil { 405 return 0, fmt.Errorf("ptraceCont: %v", err) 406 } 407 } 408} 409 410func (s *Server) Breakpoint(req *protocol.BreakpointRequest, resp *protocol.BreakpointResponse) error { 411 return s.call(s.breakpointc, req, resp) 412} 413 414func (s *Server) handleBreakpoint(req *protocol.BreakpointRequest, resp *protocol.BreakpointResponse) error { 415 return s.addBreakpoints([]uint64{req.Address}, resp) 416} 417 418func (s *Server) BreakpointAtFunction(req *protocol.BreakpointAtFunctionRequest, resp *protocol.BreakpointResponse) error { 419 return s.call(s.breakpointc, req, resp) 420} 421 422func (s *Server) handleBreakpointAtFunction(req *protocol.BreakpointAtFunctionRequest, resp *protocol.BreakpointResponse) error { 423 pc, err := s.functionStartAddress(req.Function) 424 if err != nil { 425 return err 426 } 427 return s.addBreakpoints([]uint64{pc}, resp) 428} 429 430func (s *Server) BreakpointAtLine(req *protocol.BreakpointAtLineRequest, resp *protocol.BreakpointResponse) error { 431 return s.call(s.breakpointc, req, resp) 432} 433 434func (s *Server) handleBreakpointAtLine(req *protocol.BreakpointAtLineRequest, resp *protocol.BreakpointResponse) error { 435 if s.dwarfData == nil { 436 return fmt.Errorf("no DWARF data") 437 } 438 if pcs, err := s.dwarfData.LineToBreakpointPCs(req.File, req.Line); err != nil { 439 return err 440 } else { 441 return s.addBreakpoints(pcs, resp) 442 } 443} 444 445// addBreakpoints adds breakpoints at the addresses in pcs, then stores pcs in the response. 446func (s *Server) addBreakpoints(pcs []uint64, resp *protocol.BreakpointResponse) error { 447 // Get the original code at each address with ptracePeek. 448 bps := make([]breakpoint, 0, len(pcs)) 449 for _, pc := range pcs { 450 if _, alreadySet := s.breakpoints[pc]; alreadySet { 451 continue 452 } 453 var bp breakpoint 454 if err := s.ptracePeek(s.stoppedPid, uintptr(pc), bp.origInstr[:s.arch.BreakpointSize]); err != nil { 455 return fmt.Errorf("ptracePeek: %v", err) 456 } 457 bp.pc = pc 458 bps = append(bps, bp) 459 } 460 // If all the peeks succeeded, update the list of breakpoints. 461 for _, bp := range bps { 462 s.breakpoints[bp.pc] = bp 463 } 464 resp.PCs = pcs 465 return nil 466} 467 468func (s *Server) DeleteBreakpoints(req *protocol.DeleteBreakpointsRequest, resp *protocol.DeleteBreakpointsResponse) error { 469 return s.call(s.breakpointc, req, resp) 470} 471 472func (s *Server) handleDeleteBreakpoints(req *protocol.DeleteBreakpointsRequest, resp *protocol.DeleteBreakpointsResponse) error { 473 for _, pc := range req.PCs { 474 delete(s.breakpoints, pc) 475 } 476 return nil 477} 478 479func (s *Server) setBreakpoints() error { 480 for pc := range s.breakpoints { 481 err := s.ptracePoke(s.stoppedPid, uintptr(pc), s.arch.BreakpointInstr[:s.arch.BreakpointSize]) 482 if err != nil { 483 return fmt.Errorf("setBreakpoints: %v", err) 484 } 485 } 486 return nil 487} 488 489func (s *Server) liftBreakpoints() error { 490 for pc, breakpoint := range s.breakpoints { 491 err := s.ptracePoke(s.stoppedPid, uintptr(pc), breakpoint.origInstr[:s.arch.BreakpointSize]) 492 if err != nil { 493 return fmt.Errorf("liftBreakpoints: %v", err) 494 } 495 } 496 return nil 497} 498 499func (s *Server) Eval(req *protocol.EvalRequest, resp *protocol.EvalResponse) error { 500 return s.call(s.otherc, req, resp) 501} 502 503func (s *Server) handleEval(req *protocol.EvalRequest, resp *protocol.EvalResponse) (err error) { 504 resp.Result, err = s.eval(req.Expr) 505 return err 506} 507 508// eval evaluates an expression. 509// TODO: very weak. 510func (s *Server) eval(expr string) ([]string, error) { 511 switch { 512 case strings.HasPrefix(expr, "re:"): 513 // Regular expression. Return list of symbols. 514 re, err := regexp.Compile(expr[3:]) 515 if err != nil { 516 return nil, err 517 } 518 return s.dwarfData.LookupMatchingSymbols(re) 519 520 case strings.HasPrefix(expr, "addr:"): 521 // Symbol lookup. Return address. 522 addr, err := s.functionStartAddress(expr[5:]) 523 if err != nil { 524 return nil, err 525 } 526 return []string{fmt.Sprintf("%#x", addr)}, nil 527 528 case strings.HasPrefix(expr, "val:"): 529 // Symbol lookup. Return formatted value. 530 value, err := s.printer.Sprint(expr[4:]) 531 if err != nil { 532 return nil, err 533 } 534 return []string{value}, nil 535 536 case strings.HasPrefix(expr, "src:"): 537 // Numerical address. Return file.go:123. 538 addr, err := strconv.ParseUint(expr[4:], 0, 0) 539 if err != nil { 540 return nil, err 541 } 542 file, line, err := s.lookupSource(addr) 543 if err != nil { 544 return nil, err 545 } 546 return []string{fmt.Sprintf("%s:%d", file, line)}, nil 547 548 case len(expr) > 0 && '0' <= expr[0] && expr[0] <= '9': 549 // Numerical address. Return symbol. 550 addr, err := strconv.ParseUint(expr, 0, 0) 551 if err != nil { 552 return nil, err 553 } 554 entry, _, err := s.dwarfData.PCToFunction(addr) 555 if err != nil { 556 return nil, err 557 } 558 name, ok := entry.Val(dwarf.AttrName).(string) 559 if !ok { 560 return nil, fmt.Errorf("function at 0x%x has no name", addr) 561 } 562 return []string{name}, nil 563 } 564 565 return nil, fmt.Errorf("bad expression syntax: %q", expr) 566} 567 568func (s *Server) Evaluate(req *protocol.EvaluateRequest, resp *protocol.EvaluateResponse) error { 569 return s.call(s.otherc, req, resp) 570} 571 572func (s *Server) handleEvaluate(req *protocol.EvaluateRequest, resp *protocol.EvaluateResponse) (err error) { 573 resp.Result, err = s.evalExpression(req.Expression, s.stoppedRegs.Rip, s.stoppedRegs.Rsp) 574 return err 575} 576 577func (s *Server) lookupSource(pc uint64) (file string, line uint64, err error) { 578 if s.dwarfData == nil { 579 return 580 } 581 // TODO: The gosym equivalent also returns the relevant Func. Do that when 582 // DWARF has the same facility. 583 return s.dwarfData.PCToLine(pc) 584} 585 586func (s *Server) Frames(req *protocol.FramesRequest, resp *protocol.FramesResponse) error { 587 return s.call(s.otherc, req, resp) 588} 589 590func (s *Server) handleFrames(req *protocol.FramesRequest, resp *protocol.FramesResponse) error { 591 // TODO: verify that we're stopped. 592 if s.topOfStackAddrs == nil { 593 if err := s.evaluateTopOfStackAddrs(); err != nil { 594 return err 595 } 596 } 597 598 regs := syscall.PtraceRegs{} 599 err := s.ptraceGetRegs(s.stoppedPid, ®s) 600 if err != nil { 601 return err 602 } 603 resp.Frames, err = s.walkStack(regs.Rip, regs.Rsp, req.Count) 604 return err 605} 606 607// walkStack returns up to the requested number of stack frames. 608func (s *Server) walkStack(pc, sp uint64, count int) ([]debug.Frame, error) { 609 var frames []debug.Frame 610 611 var buf [8]byte 612 b := new(bytes.Buffer) 613 r := s.dwarfData.Reader() 614 615 // TODO: handle walking over a split stack. 616 for i := 0; i < count; i++ { 617 b.Reset() 618 file, line, err := s.dwarfData.PCToLine(pc) 619 if err != nil { 620 return frames, err 621 } 622 fpOffset, err := s.dwarfData.PCToSPOffset(pc) 623 if err != nil { 624 return frames, err 625 } 626 fp := sp + uint64(fpOffset) 627 entry, funcEntry, err := s.dwarfData.PCToFunction(pc) 628 if err != nil { 629 return frames, err 630 } 631 frame := debug.Frame{ 632 PC: pc, 633 SP: sp, 634 File: file, 635 Line: line, 636 FunctionStart: funcEntry, 637 } 638 frame.Function, _ = entry.Val(dwarf.AttrName).(string) 639 r.Seek(entry.Offset) 640 for { 641 entry, err := r.Next() 642 if err != nil { 643 return frames, err 644 } 645 if entry.Tag == 0 { 646 break 647 } 648 // TODO: report variables we couldn't parse? 649 if entry.Tag == dwarf.TagFormalParameter { 650 if v, err := s.parseParameterOrLocal(entry, fp); err == nil { 651 frame.Params = append(frame.Params, debug.Param(v)) 652 } 653 } 654 if entry.Tag == dwarf.TagVariable { 655 if v, err := s.parseParameterOrLocal(entry, fp); err == nil { 656 frame.Vars = append(frame.Vars, v) 657 } 658 } 659 } 660 frames = append(frames, frame) 661 662 // Walk to the caller's PC and SP. 663 if s.topOfStack(funcEntry) { 664 break 665 } 666 err = s.ptracePeek(s.stoppedPid, uintptr(fp-uint64(s.arch.PointerSize)), buf[:s.arch.PointerSize]) 667 if err != nil { 668 return frames, fmt.Errorf("ptracePeek: %v", err) 669 } 670 pc, sp = s.arch.Uintptr(buf[:s.arch.PointerSize]), fp 671 } 672 return frames, nil 673} 674 675// parseParameterOrLocal parses the entry for a function parameter or local 676// variable, which are both specified the same way. fp contains the frame 677// pointer, which is used to calculate the variable location. 678func (s *Server) parseParameterOrLocal(entry *dwarf.Entry, fp uint64) (debug.LocalVar, error) { 679 var v debug.LocalVar 680 v.Name, _ = entry.Val(dwarf.AttrName).(string) 681 if off, err := s.dwarfData.EntryTypeOffset(entry); err != nil { 682 return v, err 683 } else { 684 v.Var.TypeID = uint64(off) 685 } 686 if i := entry.Val(dwarf.AttrLocation); i == nil { 687 return v, fmt.Errorf("missing location description") 688 } else if locationDescription, ok := i.([]uint8); !ok { 689 return v, fmt.Errorf("unsupported location description") 690 } else if offset, err := evalLocation(locationDescription); err != nil { 691 return v, err 692 } else { 693 v.Var.Address = fp + uint64(offset) 694 } 695 return v, nil 696} 697 698func (s *Server) evaluateTopOfStackAddrs() error { 699 var ( 700 lookup func(name string) (uint64, error) 701 indirect bool 702 names []string 703 ) 704 if _, err := s.dwarfData.LookupVariable("runtime.rt0_goPC"); err != nil { 705 // Look for a Go 1.3 binary (or earlier version). 706 lookup, indirect, names = s.functionStartAddress, false, []string{ 707 "runtime.goexit", 708 "runtime.mstart", 709 "runtime.mcall", 710 "runtime.morestack", 711 "runtime.lessstack", 712 "_rt0_go", 713 } 714 } else { 715 // Look for a Go 1.4 binary (or later version). 716 lookup = func(name string) (uint64, error) { 717 entry, err := s.dwarfData.LookupVariable(name) 718 if err != nil { 719 return 0, err 720 } 721 return s.dwarfData.EntryLocation(entry) 722 } 723 indirect, names = true, []string{ 724 "runtime.goexitPC", 725 "runtime.mstartPC", 726 "runtime.mcallPC", 727 "runtime.morestackPC", 728 "runtime.rt0_goPC", 729 } 730 } 731 // TODO: also look for runtime.externalthreadhandlerp, on Windows. 732 733 addrs := make([]uint64, 0, len(names)) 734 for _, name := range names { 735 addr, err := lookup(name) 736 if err != nil { 737 return err 738 } 739 addrs = append(addrs, addr) 740 } 741 742 if indirect { 743 buf := make([]byte, s.arch.PointerSize) 744 for i, addr := range addrs { 745 if err := s.ptracePeek(s.stoppedPid, uintptr(addr), buf); err != nil { 746 return fmt.Errorf("ptracePeek: %v", err) 747 } 748 addrs[i] = s.arch.Uintptr(buf) 749 } 750 } 751 752 s.topOfStackAddrs = addrs 753 return nil 754} 755 756// topOfStack is the out-of-process equivalent of runtime·topofstack. 757func (s *Server) topOfStack(funcEntry uint64) bool { 758 for _, addr := range s.topOfStackAddrs { 759 if addr == funcEntry { 760 return true 761 } 762 } 763 return false 764} 765 766func (s *Server) VarByName(req *protocol.VarByNameRequest, resp *protocol.VarByNameResponse) error { 767 return s.call(s.otherc, req, resp) 768} 769 770func (s *Server) handleVarByName(req *protocol.VarByNameRequest, resp *protocol.VarByNameResponse) error { 771 entry, err := s.dwarfData.LookupVariable(req.Name) 772 if err != nil { 773 return fmt.Errorf("variable %s: %s", req.Name, err) 774 } 775 776 loc, err := s.dwarfData.EntryLocation(entry) 777 if err != nil { 778 return fmt.Errorf("variable %s: %s", req.Name, err) 779 } 780 781 off, err := s.dwarfData.EntryTypeOffset(entry) 782 if err != nil { 783 return fmt.Errorf("variable %s: %s", req.Name, err) 784 } 785 786 resp.Var.TypeID = uint64(off) 787 resp.Var.Address = loc 788 return nil 789} 790 791func (s *Server) Value(req *protocol.ValueRequest, resp *protocol.ValueResponse) error { 792 return s.call(s.otherc, req, resp) 793} 794 795func (s *Server) handleValue(req *protocol.ValueRequest, resp *protocol.ValueResponse) error { 796 t, err := s.dwarfData.Type(dwarf.Offset(req.Var.TypeID)) 797 if err != nil { 798 return err 799 } 800 resp.Value, err = s.value(t, req.Var.Address) 801 return err 802} 803 804func (s *Server) MapElement(req *protocol.MapElementRequest, resp *protocol.MapElementResponse) error { 805 return s.call(s.otherc, req, resp) 806} 807 808func (s *Server) handleMapElement(req *protocol.MapElementRequest, resp *protocol.MapElementResponse) error { 809 t, err := s.dwarfData.Type(dwarf.Offset(req.Map.TypeID)) 810 if err != nil { 811 return err 812 } 813 m, ok := t.(*dwarf.MapType) 814 if !ok { 815 return fmt.Errorf("variable is not a map") 816 } 817 var count uint64 818 // fn will be called for each element of the map. 819 // When we reach the requested element, we fill in *resp and stop. 820 // TODO: cache locations of elements. 821 fn := func(keyAddr, valAddr uint64, keyType, valType dwarf.Type) bool { 822 count++ 823 if count == req.Index+1 { 824 resp.Key = debug.Var{TypeID: uint64(keyType.Common().Offset), Address: keyAddr} 825 resp.Value = debug.Var{TypeID: uint64(valType.Common().Offset), Address: valAddr} 826 return false 827 } 828 return true 829 } 830 if err := s.peekMapValues(m, req.Map.Address, fn); err != nil { 831 return err 832 } 833 if count <= req.Index { 834 // There weren't enough elements. 835 return fmt.Errorf("map has no element %d", req.Index) 836 } 837 return nil 838} 839 840func (s *Server) Goroutines(req *protocol.GoroutinesRequest, resp *protocol.GoroutinesResponse) error { 841 return s.call(s.otherc, req, resp) 842} 843 844const invalidStatus debug.GoroutineStatus = 99 845 846var ( 847 gStatus = [...]debug.GoroutineStatus{ 848 0: debug.Queued, // _Gidle 849 1: debug.Queued, // _Grunnable 850 2: debug.Running, // _Grunning 851 3: debug.Blocked, // _Gsyscall 852 4: debug.Blocked, // _Gwaiting 853 5: invalidStatus, // _Gmoribund_unused 854 6: invalidStatus, // _Gdead 855 7: invalidStatus, // _Genqueue 856 8: debug.Running, // _Gcopystack 857 } 858 gScanStatus = [...]debug.GoroutineStatus{ 859 0: invalidStatus, // _Gscan + _Gidle 860 1: debug.Queued, // _Gscanrunnable 861 2: debug.Running, // _Gscanrunning 862 3: debug.Blocked, // _Gscansyscall 863 4: debug.Blocked, // _Gscanwaiting 864 5: invalidStatus, // _Gscan + _Gmoribund_unused 865 6: invalidStatus, // _Gscan + _Gdead 866 7: debug.Queued, // _Gscanenqueue 867 } 868 gStatusString = [...]string{ 869 0: "idle", 870 1: "runnable", 871 2: "running", 872 3: "syscall", 873 4: "waiting", 874 8: "copystack", 875 } 876 gScanStatusString = [...]string{ 877 1: "scanrunnable", 878 2: "scanrunning", 879 3: "scansyscall", 880 4: "scanwaiting", 881 7: "scanenqueue", 882 } 883) 884 885func (s *Server) handleGoroutines(req *protocol.GoroutinesRequest, resp *protocol.GoroutinesResponse) error { 886 // Get DWARF type information for runtime.g. 887 ge, err := s.dwarfData.LookupEntry("runtime.g") 888 if err != nil { 889 return err 890 } 891 t, err := s.dwarfData.Type(ge.Offset) 892 if err != nil { 893 return err 894 } 895 gType, ok := followTypedefs(t).(*dwarf.StructType) 896 if !ok { 897 return errors.New("runtime.g is not a struct") 898 } 899 900 var ( 901 allgPtr, allgLen uint64 902 allgPtrOk bool 903 ) 904 for { 905 // Try to read the slice runtime.allgs. 906 allgsEntry, err := s.dwarfData.LookupVariable("runtime.allgs") 907 if err != nil { 908 break 909 } 910 allgsAddr, err := s.dwarfData.EntryLocation(allgsEntry) 911 if err != nil { 912 break 913 } 914 off, err := s.dwarfData.EntryTypeOffset(allgsEntry) 915 if err != nil { 916 break 917 } 918 t, err := s.dwarfData.Type(off) 919 if err != nil { 920 break 921 } 922 allgsType, ok := followTypedefs(t).(*dwarf.SliceType) 923 if !ok { 924 break 925 } 926 allgs, err := s.peekSlice(allgsType, allgsAddr) 927 if err != nil { 928 break 929 } 930 931 allgPtr, allgLen, allgPtrOk = allgs.Address, allgs.Length, true 932 break 933 } 934 if !allgPtrOk { 935 // Read runtime.allg. 936 allgEntry, err := s.dwarfData.LookupVariable("runtime.allg") 937 if err != nil { 938 return err 939 } 940 allgAddr, err := s.dwarfData.EntryLocation(allgEntry) 941 if err != nil { 942 return err 943 } 944 allgPtr, err = s.peekPtr(allgAddr) 945 if err != nil { 946 return fmt.Errorf("reading allg: %v", err) 947 } 948 949 // Read runtime.allglen. 950 allglenEntry, err := s.dwarfData.LookupVariable("runtime.allglen") 951 if err != nil { 952 return err 953 } 954 off, err := s.dwarfData.EntryTypeOffset(allglenEntry) 955 if err != nil { 956 return err 957 } 958 allglenType, err := s.dwarfData.Type(off) 959 if err != nil { 960 return err 961 } 962 allglenAddr, err := s.dwarfData.EntryLocation(allglenEntry) 963 if err != nil { 964 return err 965 } 966 switch followTypedefs(allglenType).(type) { 967 case *dwarf.UintType, *dwarf.IntType: 968 allgLen, err = s.peekUint(allglenAddr, allglenType.Common().ByteSize) 969 if err != nil { 970 return fmt.Errorf("reading allglen: %v", err) 971 } 972 default: 973 // Some runtimes don't specify the type for allglen. Assume it's uint32. 974 allgLen, err = s.peekUint(allglenAddr, 4) 975 if err != nil { 976 return fmt.Errorf("reading allglen: %v", err) 977 } 978 if allgLen != 0 { 979 break 980 } 981 // Zero? Let's try uint64. 982 allgLen, err = s.peekUint(allglenAddr, 8) 983 if err != nil { 984 return fmt.Errorf("reading allglen: %v", err) 985 } 986 } 987 } 988 989 // Initialize s.goroutineStack. 990 s.goroutineStackOnce.Do(func() { s.goroutineStackInit(gType) }) 991 992 for i := uint64(0); i < allgLen; i++ { 993 // allg is an array of pointers to g structs. Read allg[i]. 994 g, err := s.peekPtr(allgPtr + i*uint64(s.arch.PointerSize)) 995 if err != nil { 996 return err 997 } 998 gr := debug.Goroutine{} 999 1000 // Read status from the field named "atomicstatus" or "status". 1001 status, err := s.peekUintStructField(gType, g, "atomicstatus") 1002 if err != nil { 1003 status, err = s.peekUintOrIntStructField(gType, g, "status") 1004 } 1005 if err != nil { 1006 return err 1007 } 1008 if status == 6 { 1009 // _Gdead. 1010 continue 1011 } 1012 gr.Status = invalidStatus 1013 if status < uint64(len(gStatus)) { 1014 gr.Status = gStatus[status] 1015 gr.StatusString = gStatusString[status] 1016 } else if status^0x1000 < uint64(len(gScanStatus)) { 1017 gr.Status = gScanStatus[status^0x1000] 1018 gr.StatusString = gScanStatusString[status^0x1000] 1019 } 1020 if gr.Status == invalidStatus { 1021 return fmt.Errorf("unexpected goroutine status 0x%x", status) 1022 } 1023 if status == 4 || status == 0x1004 { 1024 // _Gwaiting or _Gscanwaiting. 1025 // Try reading waitreason to get a better value for StatusString. 1026 // Depending on the runtime, waitreason may be a Go string or a C string. 1027 if waitreason, err := s.peekStringStructField(gType, g, "waitreason", 80); err == nil { 1028 if waitreason != "" { 1029 gr.StatusString = waitreason 1030 } 1031 } else if ptr, err := s.peekPtrStructField(gType, g, "waitreason"); err == nil { 1032 waitreason := s.peekCString(ptr, 80) 1033 if waitreason != "" { 1034 gr.StatusString = waitreason 1035 } 1036 } 1037 } 1038 1039 gr.ID, err = s.peekIntStructField(gType, g, "goid") 1040 if err != nil { 1041 return err 1042 } 1043 1044 // Best-effort attempt to get the names of the goroutine function and the 1045 // function that created the goroutine. They aren't always available. 1046 functionName := func(pc uint64) string { 1047 entry, _, err := s.dwarfData.PCToFunction(pc) 1048 if err != nil { 1049 return "" 1050 } 1051 name, _ := entry.Val(dwarf.AttrName).(string) 1052 return name 1053 } 1054 if startpc, err := s.peekUintStructField(gType, g, "startpc"); err == nil { 1055 gr.Function = functionName(startpc) 1056 } 1057 if gopc, err := s.peekUintStructField(gType, g, "gopc"); err == nil { 1058 gr.Caller = functionName(gopc) 1059 } 1060 if gr.Status != debug.Running { 1061 // TODO: running goroutines too. 1062 gr.StackFrames, _ = s.goroutineStack(g) 1063 } 1064 1065 resp.Goroutines = append(resp.Goroutines, &gr) 1066 } 1067 1068 return nil 1069} 1070 1071// TODO: let users specify how many frames they want. 10 will be enough to 1072// determine the reason a goroutine is blocked. 1073const goroutineStackFrameCount = 10 1074 1075// goroutineStackInit initializes s.goroutineStack. 1076func (s *Server) goroutineStackInit(gType *dwarf.StructType) { 1077 // If we fail to read the DWARF data needed for s.goroutineStack, calling it 1078 // will always return the error that occurred during initialization. 1079 var err error // err is captured by the func below. 1080 s.goroutineStack = func(gAddr uint64) ([]debug.Frame, error) { 1081 return nil, err 1082 } 1083 1084 // Get g field "sched", which contains fields pc and sp. 1085 schedField, err := getField(gType, "sched") 1086 if err != nil { 1087 return 1088 } 1089 schedOffset := uint64(schedField.ByteOffset) 1090 schedType, ok := followTypedefs(schedField.Type).(*dwarf.StructType) 1091 if !ok { 1092 err = errors.New(`g field "sched" has the wrong type`) 1093 return 1094 } 1095 1096 // Get the size of the pc and sp fields and their offsets inside the g struct, 1097 // so we can quickly peek those values for each goroutine later. 1098 var ( 1099 schedPCOffset, schedSPOffset uint64 1100 schedPCByteSize, schedSPByteSize int64 1101 ) 1102 for _, x := range []struct { 1103 field string 1104 offset *uint64 1105 bytesize *int64 1106 }{ 1107 {"pc", &schedPCOffset, &schedPCByteSize}, 1108 {"sp", &schedSPOffset, &schedSPByteSize}, 1109 } { 1110 var f *dwarf.StructField 1111 f, err = getField(schedType, x.field) 1112 if err != nil { 1113 return 1114 } 1115 *x.offset = schedOffset + uint64(f.ByteOffset) 1116 switch t := followTypedefs(f.Type).(type) { 1117 case *dwarf.UintType, *dwarf.IntType: 1118 *x.bytesize = t.Common().ByteSize 1119 default: 1120 err = fmt.Errorf("gobuf field %q has the wrong type", x.field) 1121 return 1122 } 1123 } 1124 1125 s.goroutineStack = func(gAddr uint64) ([]debug.Frame, error) { 1126 schedPC, err := s.peekUint(gAddr+schedPCOffset, schedPCByteSize) 1127 if err != nil { 1128 return nil, err 1129 } 1130 schedSP, err := s.peekUint(gAddr+schedSPOffset, schedSPByteSize) 1131 if err != nil { 1132 return nil, err 1133 } 1134 return s.walkStack(schedPC, schedSP, goroutineStackFrameCount) 1135 } 1136} 1137