提交 e509c3ce 编写于 作者: A aarzilli 提交者: Derek Parker

proc: bugfix: status does not work with programs containing spaces

/proc/pid/stat needs more complex parsing

Fixes #239
上级 db95b67b
package main
import (
"fmt"
)
func fibonacci(n int, c chan int) {
x, y := 0, 1
for i := 0; i < n; i++ {
c <- x
x, y = y, x+y
}
close(c)
}
func main() {
a := struct { // set breakpoint here
A string
B int
}{A: "demo", B: 10}
fmt.Printf("%#v\n", a)
c := make(chan int, 10)
go fibonacci(cap(c), c)
for i := range c {
fmt.Println(i)
}
}
......@@ -54,6 +54,7 @@ type Process struct {
exited bool
ptraceChan chan func()
ptraceDoneChan chan interface{}
comm string
}
func New(pid int) *Process {
......@@ -142,7 +143,8 @@ func (dbp *Process) LoadInformation(path string) error {
return err
}
wg.Add(3)
wg.Add(4)
go dbp.loadProcessInformation(&wg)
go dbp.parseDebugFrame(exe, &wg)
go dbp.obtainGoSymbols(exe, &wg)
go dbp.parseDebugLineInfo(exe, &wg)
......@@ -570,7 +572,7 @@ func initializeDebugProcess(dbp *Process, path string, attach bool) (*Process, e
if err != nil {
return nil, err
}
_, _, err = wait(dbp.Pid, dbp.Pid, 0)
_, _, err = dbp.wait(dbp.Pid, 0)
if err != nil {
return nil, err
}
......
......@@ -272,7 +272,7 @@ func (dbp *Process) trapWait(pid int) (*Thread, error) {
switch port {
case dbp.os.notificationPort:
_, status, err := wait(dbp.Pid, dbp.Pid, 0)
_, status, err := dbp.wait(dbp.Pid, 0)
if err != nil {
return nil, err
}
......@@ -318,7 +318,10 @@ func (dbp *Process) trapWait(pid int) (*Thread, error) {
}
}
func wait(pid, tgid, options int) (int, *sys.WaitStatus, error) {
func (dbp *Process) loadProcessInformation(wg *sync.WaitGroup) {
}
func (dbp *Process) wait(pid, options int) (int, *sys.WaitStatus, error) {
var status sys.WaitStatus
wpid, err := sys.Wait4(pid, &status, options, nil)
return wpid, &status, err
......
......@@ -5,10 +5,12 @@ import (
"debug/gosym"
"errors"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
"sync"
"syscall"
"time"
......@@ -51,7 +53,7 @@ func Launch(cmd []string) (*Process, error) {
return nil, err
}
dbp.Pid = proc.Process.Pid
_, _, err = wait(proc.Process.Pid, proc.Process.Pid, 0)
_, _, err = dbp.wait(proc.Process.Pid, 0)
if err != nil {
return nil, fmt.Errorf("waiting for target execve failed: %s", err)
}
......@@ -73,7 +75,7 @@ func (dbp *Process) Kill() (err error) {
if err = sys.Kill(-dbp.Pid, sys.SIGKILL); err != nil {
return errors.New("could not deliver signal " + err.Error())
}
if _, _, err = wait(dbp.Pid, dbp.Pid, 0); err != nil {
if _, _, err = dbp.wait(dbp.Pid, 0); err != nil {
return
}
dbp.exited = true
......@@ -101,7 +103,7 @@ func (dbp *Process) addThread(tid int, attach bool) (*Thread, error) {
// if we truly don't have permissions.
return nil, fmt.Errorf("could not attach to new thread %d %s", tid, err)
}
pid, status, err := wait(tid, dbp.Pid, 0)
pid, status, err := dbp.wait(tid, 0)
if err != nil {
return nil, err
}
......@@ -112,7 +114,7 @@ func (dbp *Process) addThread(tid int, attach bool) (*Thread, error) {
dbp.execPtraceFunc(func() { err = syscall.PtraceSetOptions(tid, syscall.PTRACE_O_TRACECLONE) })
if err == syscall.ESRCH {
if _, _, err = wait(tid, dbp.Pid, 0); err != nil {
if _, _, err = dbp.wait(tid, 0); err != nil {
return nil, fmt.Errorf("error while waiting after adding thread: %d %s", tid, err)
}
dbp.execPtraceFunc(func() { err = syscall.PtraceSetOptions(tid, syscall.PTRACE_O_TRACECLONE) })
......@@ -239,7 +241,7 @@ func (dbp *Process) parseDebugLineInfo(exe *elf.File, wg *sync.WaitGroup) {
func (dbp *Process) trapWait(pid int) (*Thread, error) {
for {
wpid, status, err := wait(pid, dbp.Pid, 0)
wpid, status, err := dbp.wait(pid, 0)
if err != nil {
return nil, fmt.Errorf("wait err %s %d", err, pid)
}
......@@ -309,25 +311,44 @@ func (dbp *Process) trapWait(pid int) (*Thread, error) {
}
}
func status(pid int) rune {
func (dbp *Process) loadProcessInformation(wg *sync.WaitGroup) {
defer wg.Done()
comm, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/comm", dbp.Pid))
if err != nil {
fmt.Printf("Could not read process comm name: %v\n", err)
os.Exit(1)
}
// removes newline character
comm = comm[:len(comm)-1]
dbp.comm = strings.Replace(string(comm), "%", "%%", -1)
}
func status(pid int, comm string) rune {
// The second field of /proc/pid/stat is the name of the task in parenthesis.
// The name of the task is the base name of the executable for this process limited to 15 characters
// Since both parenthesis and spaces can appear inside the name of the task and no escaping happens we need to read the name of the executable first
// See: include/linux/sched.c:315 and include/linux/sched.c:1510
f, err := os.Open(fmt.Sprintf("/proc/%d/stat", pid))
if err != nil {
return '\000'
}
defer f.Close()
var (
p int
comm string
state rune
)
fmt.Fscanf(f, "%d %s %c", &p, &comm, &state)
fmt.Fscanf(f, "%d ("+comm+") %c", &p, &state)
return state
}
func wait(pid, tgid, options int) (int, *sys.WaitStatus, error) {
func (dbp *Process) wait(pid, options int) (int, *sys.WaitStatus, error) {
var s sys.WaitStatus
if (pid != tgid) || (options != 0) {
if (pid != dbp.Pid) || (options != 0) {
wpid, err := sys.Wait4(pid, &s, sys.WALL|options, nil)
return wpid, &s, err
} else {
......@@ -350,7 +371,7 @@ func wait(pid, tgid, options int) (int, *sys.WaitStatus, error) {
if wpid != 0 {
return wpid, &s, err
}
if status(pid) == STATUS_ZOMBIE {
if status(pid, dbp.comm) == STATUS_ZOMBIE {
return pid, nil, nil
}
time.Sleep(200 * time.Millisecond)
......
......@@ -800,3 +800,13 @@ func TestProcessReceivesSIGCHLD(t *testing.T) {
}
})
}
func TestIssue239(t *testing.T) {
withTestProcess("is sue239", t, func(p *Process, fixture protest.Fixture) {
pos, _, err := p.goSymTable.LineToPC(fixture.Source, 17)
assertNoError(err, t, "LineToPC()")
_, err = p.SetBreakpoint(pos)
assertNoError(err, t, fmt.Sprintf("SetBreakpoint(%d)", pos))
assertNoError(p.Continue(), t, fmt.Sprintf("Continue()"))
})
}
......@@ -18,7 +18,7 @@ func (t *Thread) halt() (err error) {
err = fmt.Errorf("halt err %s on thread %d", err, t.Id)
return
}
_, _, err = wait(t.Id, t.dbp.Pid, 0)
_, _, err = t.dbp.wait(t.Id, 0)
if err != nil {
err = fmt.Errorf("wait err %s on thread %d", err, t.Id)
return
......@@ -27,7 +27,7 @@ func (t *Thread) halt() (err error) {
}
func (thread *Thread) stopped() bool {
state := status(thread.Id)
state := status(thread.Id, thread.dbp.comm)
return state == STATUS_TRACE_STOP
}
......@@ -42,7 +42,7 @@ func (t *Thread) singleStep() (err error) {
if err != nil {
return err
}
_, _, err = wait(t.Id, t.dbp.Pid, 0)
_, _, err = t.dbp.wait(t.Id, 0)
return err
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册