ogle: new arch package for architecture-dependent details
Put the details into a struct for each arch, and have the
server choose the appropriate one.
TODO: For now, the AMD64 architecture is hard-wired.
LGTM=nigeltao
R=nigeltao
https://golang.org/cl/85860043
diff --git a/arch/arch.go b/arch/arch.go
new file mode 100644
index 0000000..92945ab
--- /dev/null
+++ b/arch/arch.go
@@ -0,0 +1,66 @@
+// Copyright 2014 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 arch contains architecture-specific definitions.
+package arch
+
+import (
+ "encoding/binary"
+)
+
+const MaxBreakpointSize = 4 // TODO
+
+// Architecture defines the architecture-specific details for a given machine.
+type Architecture struct {
+ // BreakpointSize is the size of a breakpoint instruction, in bytes.
+ BreakpointSize int
+ // IntSize is the size of the int type, in bytes.
+ IntSize int
+ // PointerSize is the size of a pointer, in bytes.
+ PointerSize int
+ // The byte order for I/O.
+ ByteOrder binary.ByteOrder
+ BreakpointInstr [MaxBreakpointSize]byte
+}
+
+func (a *Architecture) Int(buf []byte) int64 {
+ return int64(a.Uint(buf))
+}
+
+func (a *Architecture) Uint(buf []byte) uint64 {
+ if len(buf) != a.IntSize {
+ panic("bad uint size")
+ }
+ switch a.IntSize {
+ case 4:
+ return uint64(a.ByteOrder.Uint32(buf[:4]))
+ case 8:
+ return a.ByteOrder.Uint64(buf[:8])
+ }
+ panic("no uint size")
+}
+
+var AMD64 = Architecture{
+ BreakpointSize: 1,
+ IntSize: 8,
+ PointerSize: 8,
+ ByteOrder: binary.LittleEndian,
+ BreakpointInstr: [MaxBreakpointSize]byte{0xCC}, // INT 3
+}
+
+var X86 = Architecture{
+ BreakpointSize: 1,
+ IntSize: 4,
+ PointerSize: 4,
+ ByteOrder: binary.LittleEndian,
+ BreakpointInstr: [MaxBreakpointSize]byte{0xCC}, // INT 3
+}
+
+var ARM = Architecture{
+ BreakpointSize: 4, // TODO
+ IntSize: 4,
+ PointerSize: 4,
+ ByteOrder: binary.LittleEndian,
+ BreakpointInstr: [MaxBreakpointSize]byte{0x00, 0x00, 0x00, 0x00}, // TODO
+}
diff --git a/program/server/server.go b/program/server/server.go
index 8497efa..687f632 100644
--- a/program/server/server.go
+++ b/program/server/server.go
@@ -7,7 +7,6 @@
package server
import (
- "encoding/binary"
"fmt"
"os"
"regexp"
@@ -20,16 +19,18 @@
"code.google.com/p/ogle/debug/elf"
"code.google.com/p/ogle/debug/macho"
+ "code.google.com/p/ogle/arch"
"code.google.com/p/ogle/program"
"code.google.com/p/ogle/program/proxyrpc"
)
type breakpoint struct {
pc uint64
- origInstr byte // TODO: don't be amd64-specific.
+ origInstr [arch.MaxBreakpointSize]byte
}
type Server struct {
+ arch arch.Architecture
executable string // Name of executable.
dwarfData *dwarf.Data
@@ -56,6 +57,7 @@
return nil, err
}
srv := &Server{
+ arch: arch.AMD64, // TODO: How do we discover this?
executable: executable,
dwarfData: dwarfData,
fc: make(chan func() error),
@@ -218,7 +220,7 @@
return err
}
- regs.Rip-- // TODO: depends on length of trap.
+ regs.Rip -= uint64(s.arch.BreakpointSize)
err = s.ptraceSetRegs(s.proc.Pid, ®s)
if err != nil {
return fmt.Errorf("ptraceSetRegs: %v", err)
@@ -237,6 +239,7 @@
if err != nil {
return err
}
+ var bp breakpoint
for _, addr := range addrs {
pc, err := s.evalAddress(addr)
if err != nil {
@@ -246,22 +249,20 @@
return fmt.Errorf("breakpoint already set at %#x (TODO)", pc)
}
- var buf [1]byte
- err = s.ptracePeek(s.proc.Pid, uintptr(pc), buf[:])
+ err = s.ptracePeek(s.proc.Pid, uintptr(pc), bp.origInstr[:s.arch.BreakpointSize])
if err != nil {
- return fmt.Errorf("ptracePoke: %v", err)
+ return fmt.Errorf("ptracePeek: %v", err)
}
- s.breakpoints[pc] = breakpoint{pc: pc, origInstr: buf[0]}
+ bp.pc = pc
+ s.breakpoints[pc] = bp
}
return nil
}
func (s *Server) setBreakpoints() error {
- var buf [1]byte
- buf[0] = 0xcc // INT 3 instruction on x86.
for pc := range s.breakpoints {
- err := s.ptracePoke(s.proc.Pid, uintptr(pc), buf[:])
+ err := s.ptracePoke(s.proc.Pid, uintptr(pc), s.arch.BreakpointInstr[:s.arch.BreakpointSize])
if err != nil {
return fmt.Errorf("setBreakpoints: %v", err)
}
@@ -270,10 +271,8 @@
}
func (s *Server) liftBreakpoints() error {
- var buf [1]byte
for pc, breakpoint := range s.breakpoints {
- buf[0] = breakpoint.origInstr
- err := s.ptracePoke(s.proc.Pid, uintptr(pc), buf[:])
+ err := s.ptracePoke(s.proc.Pid, uintptr(pc), breakpoint.origInstr[:s.arch.BreakpointSize])
if err != nil {
return fmt.Errorf("liftBreakpoints: %v", err)
}
@@ -360,7 +359,7 @@
if err != nil {
return err
}
- fp := regs.Rsp + 8 // TODO: 8 for the return address is amd64 specific.
+ fp := regs.Rsp + uint64(s.arch.PointerSize)
entry, err := s.entryForPC(regs.Rip)
if err != nil {
@@ -401,19 +400,17 @@
if err == nil {
frame.S += fmt.Sprintf("[%v]", t)
}
- // TODO: don't assume amd64.
- if t.String() != "int" && t.Size() == 8 {
+ if t.String() != "int" || t.Size() != int64(s.arch.IntSize) {
break
}
if location == 0 {
return fmt.Errorf("no location for FormalParameter")
}
- err = s.ptracePeek(s.proc.Pid, location, buf[:8])
+ err = s.ptracePeek(s.proc.Pid, location, buf[:s.arch.IntSize])
if err != nil {
return err
}
- // TODO: don't assume little-endian.
- frame.S += fmt.Sprintf("==%#x", binary.LittleEndian.Uint64(buf[:8]))
+ frame.S += fmt.Sprintf("==%#x", s.arch.Int(buf[:s.arch.IntSize]))
}
}
}