Initial contribution
diff --git a/src/cmd/pprof/pprof.go b/src/cmd/pprof/pprof.go
new file mode 100644
index 0000000..44f4f6c
--- /dev/null
+++ b/src/cmd/pprof/pprof.go
@@ -0,0 +1,237 @@
+// 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 main
+
+import (
+	"debug/gosym"
+	"flag"
+	"fmt"
+	"os"
+	"regexp"
+	"strings"
+	"sync"
+
+	"cmd/internal/objfile"
+	"cmd/pprof/internal/commands"
+	"cmd/pprof/internal/driver"
+	"cmd/pprof/internal/fetch"
+	"cmd/pprof/internal/plugin"
+	"cmd/pprof/internal/profile"
+	"cmd/pprof/internal/symbolizer"
+	"cmd/pprof/internal/symbolz"
+)
+
+func main() {
+	var extraCommands map[string]*commands.Command // no added Go-specific commands
+	if err := driver.PProf(flags{}, fetch.Fetcher, symbolize, new(objTool), plugin.StandardUI(), extraCommands); err != nil {
+		fmt.Fprintf(os.Stderr, "%v\n", err)
+	}
+}
+
+// symbolize attempts to symbolize profile p.
+// If the source is a local binary, it tries using symbolizer and obj.
+// If the source is a URL, it fetches symbol information using symbolz.
+func symbolize(mode, source string, p *profile.Profile, obj plugin.ObjTool, ui plugin.UI) error {
+	remote, local := true, true
+	for _, o := range strings.Split(strings.ToLower(mode), ":") {
+		switch o {
+		case "none", "no":
+			return nil
+		case "local":
+			remote, local = false, true
+		case "remote":
+			remote, local = true, false
+		default:
+			ui.PrintErr("ignoring unrecognized symbolization option: " + mode)
+			ui.PrintErr("expecting -symbolize=[local|remote|none][:force]")
+			fallthrough
+		case "", "force":
+			// Ignore these options, -force is recognized by symbolizer.Symbolize
+		}
+	}
+
+	var err error
+	if local {
+		// Symbolize using binutils.
+		if err = symbolizer.Symbolize(mode, p, obj, ui); err == nil {
+			return nil
+		}
+	}
+	if remote {
+		err = symbolz.Symbolize(source, fetch.PostURL, p)
+	}
+	return err
+}
+
+// flags implements the driver.FlagPackage interface using the builtin flag package.
+type flags struct {
+}
+
+func (flags) Bool(o string, d bool, c string) *bool {
+	return flag.Bool(o, d, c)
+}
+
+func (flags) Int(o string, d int, c string) *int {
+	return flag.Int(o, d, c)
+}
+
+func (flags) Float64(o string, d float64, c string) *float64 {
+	return flag.Float64(o, d, c)
+}
+
+func (flags) String(o, d, c string) *string {
+	return flag.String(o, d, c)
+}
+
+func (flags) Parse(usage func()) []string {
+	flag.Usage = usage
+	flag.Parse()
+	args := flag.Args()
+	if len(args) == 0 {
+		usage()
+	}
+	return args
+}
+
+func (flags) ExtraUsage() string {
+	return ""
+}
+
+// objTool implements plugin.ObjTool using Go libraries
+// (instead of invoking GNU binutils).
+type objTool struct {
+	mu          sync.Mutex
+	disasmCache map[string]*objfile.Disasm
+}
+
+func (*objTool) Open(name string, start uint64) (plugin.ObjFile, error) {
+	of, err := objfile.Open(name)
+	if err != nil {
+		return nil, err
+	}
+	f := &file{
+		name: name,
+		file: of,
+	}
+	return f, nil
+}
+
+func (*objTool) Demangle(names []string) (map[string]string, error) {
+	// No C++, nothing to demangle.
+	return make(map[string]string), nil
+}
+
+func (t *objTool) Disasm(file string, start, end uint64) ([]plugin.Inst, error) {
+	d, err := t.cachedDisasm(file)
+	if err != nil {
+		return nil, err
+	}
+	var asm []plugin.Inst
+	d.Decode(start, end, func(pc, size uint64, file string, line int, text string) {
+		asm = append(asm, plugin.Inst{Addr: pc, File: file, Line: line, Text: text})
+	})
+	return asm, nil
+}
+
+func (t *objTool) cachedDisasm(file string) (*objfile.Disasm, error) {
+	t.mu.Lock()
+	defer t.mu.Unlock()
+	if t.disasmCache == nil {
+		t.disasmCache = make(map[string]*objfile.Disasm)
+	}
+	d := t.disasmCache[file]
+	if d != nil {
+		return d, nil
+	}
+	f, err := objfile.Open(file)
+	if err != nil {
+		return nil, err
+	}
+	d, err = f.Disasm()
+	f.Close()
+	if err != nil {
+		return nil, err
+	}
+	t.disasmCache[file] = d
+	return d, nil
+}
+
+func (*objTool) SetConfig(config string) {
+	// config is usually used to say what binaries to invoke.
+	// Ignore entirely.
+}
+
+// file implements plugin.ObjFile using Go libraries
+// (instead of invoking GNU binutils).
+// A file represents a single executable being analyzed.
+type file struct {
+	name string
+	sym  []objfile.Sym
+	file *objfile.File
+	pcln *gosym.Table
+}
+
+func (f *file) Name() string {
+	return f.name
+}
+
+func (f *file) Base() uint64 {
+	// No support for shared libraries.
+	return 0
+}
+
+func (f *file) BuildID() string {
+	// No support for build ID.
+	return ""
+}
+
+func (f *file) SourceLine(addr uint64) ([]plugin.Frame, error) {
+	if f.pcln == nil {
+		pcln, err := f.file.PCLineTable()
+		if err != nil {
+			return nil, err
+		}
+		f.pcln = pcln
+	}
+	file, line, fn := f.pcln.PCToLine(addr)
+	if fn == nil {
+		return nil, fmt.Errorf("no line information for PC=%#x", addr)
+	}
+	frame := []plugin.Frame{
+		{
+			Func: fn.Name,
+			File: file,
+			Line: line,
+		},
+	}
+	return frame, nil
+}
+
+func (f *file) Symbols(r *regexp.Regexp, addr uint64) ([]*plugin.Sym, error) {
+	if f.sym == nil {
+		sym, err := f.file.Symbols()
+		if err != nil {
+			return nil, err
+		}
+		f.sym = sym
+	}
+	var out []*plugin.Sym
+	for _, s := range f.sym {
+		if (r == nil || r.MatchString(s.Name)) && (addr == 0 || s.Addr <= addr && addr < s.Addr+uint64(s.Size)) {
+			out = append(out, &plugin.Sym{
+				Name:  []string{s.Name},
+				File:  f.name,
+				Start: s.Addr,
+				End:   s.Addr + uint64(s.Size) - 1,
+			})
+		}
+	}
+	return out, nil
+}
+
+func (f *file) Close() error {
+	f.file.Close()
+	return nil
+}