summaryrefslogtreecommitdiff
path: root/usr/austin/ogle/process.go
blob: 0ca8940729675eb66692113b26ed8908cfcd8140 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// Copyright 2009 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ogle

import (
	"eval";
	"ptrace";
	"reflect";
	"os";
	"sym";
)

// A FormatError indicates a failure to process information in or
// about a remote process, such as unexpected or missing information
// in the object file or runtime structures.
type FormatError string

func (e FormatError) String() string {
	return string(e);
}

// An UnknownArchitecture occurs when trying to load an object file
// that indicates an architecture not supported by the debugger.
type UnknownArchitecture sym.ElfMachine

func (e UnknownArchitecture) String() string {
	return "unknown architecture: " + sym.ElfMachine(e).String();
}

// A Process represents a remote attached process.
type Process struct {
	Arch;
	ptrace.Process;

	// The symbol table of this process
	syms *sym.GoSymTable;

	// Current thread
	thread ptrace.Thread;
	// Current frame, or nil if the current thread is not stopped
	frame *frame;

	// Types parsed from the remote process
	types map[ptrace.Word] *remoteType;

	// Types and values from the remote runtime package
	runtime runtimeValues;

	// Runtime field indexes
	f runtimeIndexes;
}

// NewProcess constructs a new remote process around a ptrace'd
// process, an architecture, and a symbol table.
func NewProcess(proc ptrace.Process, arch Arch, syms *sym.GoSymTable) *Process {
	p := &Process{
		Arch: arch,
		Process: proc,
		syms: syms,
		thread: proc.Threads()[0],
		types: make(map[ptrace.Word] *remoteType),
	};

	// TODO(austin) Set p.frame if proc is stopped

	p.bootstrap();
	return p;
}

// NewProcessElf constructs a new remote process around a ptrace'd
// process and the process' ELF object.
func NewProcessElf(proc ptrace.Process, elf *sym.Elf) (*Process, os.Error) {
	syms, err := sym.ElfGoSyms(elf);
	if err != nil {
		return nil, err;
	}
	if syms == nil {
		return nil, FormatError("Failed to find symbol table");
	}
	var arch Arch;
	switch elf.Machine {
	case sym.ElfX86_64:
		arch = Amd64;
	default:
		return nil, UnknownArchitecture(elf.Machine);
	}
	return NewProcess(proc, arch, syms), nil;
}

// bootstrap constructs the runtime structure of a remote process.
func (p *Process) bootstrap() {
	// Manually construct runtime types
	p.runtime.String = newManualType(eval.TypeOfNative(rt1String{}), p.Arch);
	p.runtime.Slice = newManualType(eval.TypeOfNative(rt1Slice{}), p.Arch);
	p.runtime.Eface = newManualType(eval.TypeOfNative(rt1Eface{}), p.Arch);

	p.runtime.Type = newManualType(eval.TypeOfNative(rt1Type{}), p.Arch);
	p.runtime.CommonType = newManualType(eval.TypeOfNative(rt1CommonType{}), p.Arch);
	p.runtime.UncommonType = newManualType(eval.TypeOfNative(rt1UncommonType{}), p.Arch);
	p.runtime.StructField = newManualType(eval.TypeOfNative(rt1StructField{}), p.Arch);
	p.runtime.StructType = newManualType(eval.TypeOfNative(rt1StructType{}), p.Arch);
	p.runtime.PtrType = newManualType(eval.TypeOfNative(rt1PtrType{}), p.Arch);
	p.runtime.ArrayType = newManualType(eval.TypeOfNative(rt1ArrayType{}), p.Arch);
	p.runtime.SliceType = newManualType(eval.TypeOfNative(rt1SliceType{}), p.Arch);

	p.runtime.Stktop = newManualType(eval.TypeOfNative(rt1Stktop{}), p.Arch);
	p.runtime.Gobuf = newManualType(eval.TypeOfNative(rt1Gobuf{}), p.Arch);
	p.runtime.G = newManualType(eval.TypeOfNative(rt1G{}), p.Arch);

	// Get addresses of type·*runtime.XType for discrimination.
	rtv := reflect.Indirect(reflect.NewValue(&p.runtime)).(*reflect.StructValue);
	rtvt := rtv.Type().(*reflect.StructType);
	for i := 0; i < rtv.NumField(); i++ {
		n := rtvt.Field(i).Name;
		if n[0] != 'P' || n[1] < 'A' || n[1] > 'Z' {
			continue;
		}
		sym := p.syms.SymFromName("type·*runtime." + n[1:len(n)]);
		if sym == nil {
			continue;
		}
		rtv.Field(i).(*reflect.Uint64Value).Set(sym.Common().Value);
	}

	// Get field indexes
	fillRuntimeIndexes(&p.runtime, &p.f);
}