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])) } } }