ogle/program/server: use dwarf data directly, instead of gosym.

LGTM=r
R=r
https://golang.org/cl/81240045
diff --git a/program/server/dwarf.go b/program/server/dwarf.go
new file mode 100644
index 0000000..44321bc
--- /dev/null
+++ b/program/server/dwarf.go
@@ -0,0 +1,164 @@
+// 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 server
+
+import (
+	"fmt"
+	"regexp"
+
+	"code.google.com/p/ogle/debug/dwarf"
+)
+
+func (s *Server) lookupRE(re *regexp.Regexp) (result []string, err error) {
+	r := s.dwarfData.Reader()
+	for {
+		entry, err := r.Next()
+		if err != nil {
+			return nil, err
+		}
+		if entry == nil {
+			// TODO: why don't we get an error here.
+			break
+		}
+		if entry.Tag != dwarf.TagSubprogram {
+			continue
+		}
+		nameAttr := lookupAttr(entry, dwarf.AttrName)
+		if nameAttr == nil {
+			// TODO: this shouldn't be possible.
+			continue
+		}
+		name, ok := nameAttr.(string)
+		if !ok || !re.MatchString(name) {
+			continue
+		}
+		result = append(result, name)
+	}
+	return result, nil
+}
+
+func (s *Server) lookupSym(name string) (uint64, error) {
+	r := s.dwarfData.Reader()
+	for {
+		entry, err := r.Next()
+		if err != nil {
+			return 0, err
+		}
+		if entry == nil {
+			// TODO: why don't we get an error here.
+			break
+		}
+		if entry.Tag != dwarf.TagSubprogram {
+			continue
+		}
+		nameAttr := lookupAttr(entry, dwarf.AttrName)
+		if nameAttr == nil {
+			// TODO: this shouldn't be possible.
+			continue
+		}
+		if nameAttr.(string) != name {
+			continue
+		}
+		addrAttr := lookupAttr(entry, dwarf.AttrLowpc)
+		if addrAttr == nil {
+			return 0, fmt.Errorf("symbol %q has no LowPC attribute", name)
+		}
+		addr, ok := addrAttr.(uint64)
+		if !ok {
+			return 0, fmt.Errorf("symbol %q has non-uint64 LowPC attribute", name)
+		}
+		return addr, nil
+	}
+	return 0, fmt.Errorf("symbol %q not found", name)
+}
+
+func (s *Server) lookupPC(pc uint64) (string, error) {
+	r := s.dwarfData.Reader()
+	for {
+		entry, err := r.Next()
+		if err != nil {
+			return "", err
+		}
+		if entry == nil {
+			// TODO: why don't we get an error here.
+			break
+		}
+		if entry.Tag != dwarf.TagSubprogram {
+			continue
+		}
+		lowpc, lok := lookupAttr(entry, dwarf.AttrLowpc).(uint64)
+		highpc, hok := lookupAttr(entry, dwarf.AttrHighpc).(uint64)
+		if !lok || !hok || pc < lowpc || highpc <= pc {
+			continue
+		}
+		nameAttr := lookupAttr(entry, dwarf.AttrName)
+		if nameAttr == nil {
+			// TODO: this shouldn't be possible.
+			continue
+		}
+		name, ok := nameAttr.(string)
+		if !ok {
+			return "", fmt.Errorf("name for PC %#x is not a string", pc)
+		}
+		return name, nil
+	}
+	return "", fmt.Errorf("PC %#x not found", pc)
+}
+
+func lookupAttr(e *dwarf.Entry, a dwarf.Attr) interface{} {
+	for _, f := range e.Field {
+		if f.Attr == a {
+			return f.Val
+		}
+	}
+	return nil
+}
+
+func evalLocation(v []uint8) string {
+	if len(v) == 0 {
+		return "<nil>"
+	}
+	if v[0] != 0x9C { // DW_OP_call_frame_cfa
+		return "UNK0"
+	}
+	if len(v) == 1 {
+		return "0"
+	}
+	v = v[1:]
+	if v[0] != 0x11 { // DW_OP_consts
+		return "UNK1"
+	}
+	return fmt.Sprintf("%x", sleb128(v[1:]))
+}
+
+func uleb128(v []uint8) (u uint64) {
+	var shift uint
+	for _, x := range v {
+		u |= (uint64(x) & 0x7F) << shift
+		shift += 7
+		if x&0x80 == 0 {
+			break
+		}
+	}
+	return u
+}
+
+func sleb128(v []uint8) (s int64) {
+	var shift uint
+	var sign int64 = -1
+	for _, x := range v {
+		s |= (int64(x) & 0x7F) << shift
+		shift += 7
+		sign <<= 7
+		if x&0x80 == 0 {
+			if x&0x40 != 0 {
+				s |= sign
+			}
+			break
+		}
+	}
+	// Sign extend?
+	return s
+}
diff --git a/program/server/server.go b/program/server/server.go
index d08ed47..372d172 100644
--- a/program/server/server.go
+++ b/program/server/server.go
@@ -15,11 +15,10 @@
 	"sync"
 	"syscall"
 
-	"debug/elf"
-	"debug/macho"
-	"debug/pe"
+	"code.google.com/p/ogle/debug/dwarf"
+	"code.google.com/p/ogle/debug/elf"
+	"code.google.com/p/ogle/debug/macho"
 
-	"code.google.com/p/ogle/gosym"
 	"code.google.com/p/ogle/program"
 	"code.google.com/p/ogle/program/proxyrpc"
 )
@@ -31,8 +30,7 @@
 
 type Server struct {
 	executable string // Name of executable.
-	lines      *gosym.LineTable
-	symbols    *gosym.Table
+	dwarfData  *dwarf.Data
 
 	mu sync.Mutex
 
@@ -52,19 +50,13 @@
 		return nil, err
 	}
 	defer fd.Close()
-	textStart, symtab, pclntab, err := loadTables(fd)
-	if err != nil {
-		return nil, err
-	}
-	lines := gosym.NewLineTable(pclntab, textStart)
-	symbols, err := gosym.NewTable(symtab, lines)
+	dwarfData, err := loadDwarfData(fd)
 	if err != nil {
 		return nil, err
 	}
 	srv := &Server{
 		executable:  executable,
-		lines:       lines,
-		symbols:     symbols,
+		dwarfData:   dwarfData,
 		fc:          make(chan func() error),
 		ec:          make(chan error),
 		breakpoints: make(map[uint64]breakpoint),
@@ -73,62 +65,14 @@
 	return srv, nil
 }
 
-// This function is copied from $GOROOT/src/cmd/addr2line/main.go.
-// TODO: Make this architecture-defined? Push into gosym?
-// TODO: Why is the .gosymtab always empty?
-func loadTables(f *os.File) (textStart uint64, symtab, pclntab []byte, err error) {
+func loadDwarfData(f *os.File) (*dwarf.Data, error) {
 	if obj, err := elf.NewFile(f); err == nil {
-		if sect := obj.Section(".text"); sect != nil {
-			textStart = sect.Addr
-		}
-		if sect := obj.Section(".gosymtab"); sect != nil {
-			if symtab, err = sect.Data(); err != nil {
-				return 0, nil, nil, err
-			}
-		}
-		if sect := obj.Section(".gopclntab"); sect != nil {
-			if pclntab, err = sect.Data(); err != nil {
-				return 0, nil, nil, err
-			}
-		}
-		return textStart, symtab, pclntab, nil
+		return obj.DWARF()
 	}
-
 	if obj, err := macho.NewFile(f); err == nil {
-		if sect := obj.Section("__text"); sect != nil {
-			textStart = sect.Addr
-		}
-		if sect := obj.Section("__gosymtab"); sect != nil {
-			if symtab, err = sect.Data(); err != nil {
-				return 0, nil, nil, err
-			}
-		}
-		if sect := obj.Section("__gopclntab"); sect != nil {
-			if pclntab, err = sect.Data(); err != nil {
-				return 0, nil, nil, err
-			}
-		}
-		return textStart, symtab, pclntab, nil
+		return obj.DWARF()
 	}
-
-	if obj, err := pe.NewFile(f); err == nil {
-		if sect := obj.Section(".text"); sect != nil {
-			textStart = uint64(sect.VirtualAddress)
-		}
-		if sect := obj.Section(".gosymtab"); sect != nil {
-			if symtab, err = sect.Data(); err != nil {
-				return 0, nil, nil, err
-			}
-		}
-		if sect := obj.Section(".gopclntab"); sect != nil {
-			if pclntab, err = sect.Data(); err != nil {
-				return 0, nil, nil, err
-			}
-		}
-		return textStart, symtab, pclntab, nil
-	}
-
-	return 0, nil, nil, fmt.Errorf("unrecognized binary format")
+	return nil, fmt.Errorf("unrecognized binary format")
 }
 
 type file struct {
@@ -337,27 +281,19 @@
 	switch {
 	case strings.HasPrefix(expr, "re:"):
 		// Regular expression. Return list of symbols.
-		expr = expr[3:]
-		re, err := regexp.Compile(expr)
+		re, err := regexp.Compile(expr[3:])
 		if err != nil {
 			return nil, err
 		}
-		strs := make([]string, 0, 100)
-		for _, f := range s.symbols.Funcs {
-			if re.MatchString(f.Sym.Name) {
-				strs = append(strs, f.Sym.Name)
-			}
-		}
-		return strs, nil
+		return s.lookupRE(re)
 
 	case strings.HasPrefix(expr, "sym:"):
 		// Symbol lookup. Return address.
-		expr = expr[4:]
-		sym := s.symbols.LookupFunc(expr)
-		if sym == nil {
-			return nil, fmt.Errorf("symbol %q not found", expr)
+		addr, err := s.lookupSym(expr[4:])
+		if err != nil {
+			return nil, err
 		}
-		return []string{fmt.Sprintf("%#x", sym.Value)}, nil
+		return []string{fmt.Sprintf("%#x", addr)}, nil
 
 	case len(expr) > 0 && '0' <= expr[0] && expr[0] <= '9':
 		// Numerical address. Return symbol.
@@ -365,11 +301,11 @@
 		if err != nil {
 			return nil, err
 		}
-		fun := s.symbols.PCToFunc(addr)
-		if fun == nil {
-			return nil, fmt.Errorf("address %q has no func", expr)
+		funcName, err := s.lookupPC(addr)
+		if err != nil {
+			return nil, err
 		}
-		return []string{fun.Sym.Name}, nil
+		return []string{funcName}, nil
 	}
 
 	return nil, fmt.Errorf("bad expression syntax: %q", expr)
@@ -379,17 +315,16 @@
 // and evaluates it as an address.
 func (s *Server) evalAddress(expr string) (uint64, error) {
 	// Might be a symbol.
-	sym := s.symbols.LookupFunc(expr)
-	if sym != nil {
-		return sym.Value, nil
+	addr, err := s.lookupSym(expr)
+	if err == nil {
+		return addr, nil
 	}
 
 	// Must be a number.
-	addr, err := strconv.ParseUint(expr, 0, 0)
+	addr, err = strconv.ParseUint(expr, 0, 0)
 	if err != nil {
 		return 0, fmt.Errorf("eval: %q is neither symbol nor number", expr)
 	}
 
 	return addr, nil
-
 }