mirror of
https://github.com/golang/go
synced 2024-11-05 19:46:11 -07:00
d30e00c240
splitdwarf osxMachoFile [ osxDsymFile ] splitdwarf takes an executable produced by go build as input, and uncompresses and copies the DWARF segment into a separate file in the way that is expected by OSX-hosted tools (lldb and ports of gdb). If osxDsymFile is not named explicitly, the default of "<osxMachoFile>.dSYM/Contents/Resources/DWARF/<osxMachoFile>" is used instead, with directories created as needed. If the input file contains no UUID, then one is created by hashing non-DWARF segment contents, and added to the executable. This is necessary because gdb and lldb both expect matching UUIDs to be present in the executable and its debugging symbols. Includes a modified version of debug/macho, with additional definitions and the ability to write segments, sections, and some MachO load commands added. Change-Id: Ia5b0e289260f72bbca392cdf2c7c0a75e3ca40e5 Reviewed-on: https://go-review.googlesource.com/c/143357 Reviewed-by: Austin Clements <austin@google.com>
469 lines
11 KiB
Go
469 lines
11 KiB
Go
// 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.
|
|
|
|
// Mach-O header data structures
|
|
// http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html
|
|
|
|
package macho
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"strconv"
|
|
)
|
|
|
|
// A FileHeader represents a Mach-O file header.
|
|
type FileHeader struct {
|
|
Magic uint32
|
|
Cpu Cpu
|
|
SubCpu uint32
|
|
Type HdrType
|
|
NCommands uint32 // number of load commands
|
|
SizeCommands uint32 // size of all the load commands, not including this header.
|
|
Flags HdrFlags
|
|
}
|
|
|
|
func (h *FileHeader) Put(b []byte, o binary.ByteOrder) int {
|
|
o.PutUint32(b[0:], h.Magic)
|
|
o.PutUint32(b[4:], uint32(h.Cpu))
|
|
o.PutUint32(b[8:], h.SubCpu)
|
|
o.PutUint32(b[12:], uint32(h.Type))
|
|
o.PutUint32(b[16:], h.NCommands)
|
|
o.PutUint32(b[20:], h.SizeCommands)
|
|
o.PutUint32(b[24:], uint32(h.Flags))
|
|
if h.Magic == Magic32 {
|
|
return 28
|
|
}
|
|
o.PutUint32(b[28:], 0)
|
|
return 32
|
|
}
|
|
|
|
const (
|
|
fileHeaderSize32 = 7 * 4
|
|
fileHeaderSize64 = 8 * 4
|
|
)
|
|
|
|
const (
|
|
Magic32 uint32 = 0xfeedface
|
|
Magic64 uint32 = 0xfeedfacf
|
|
MagicFat uint32 = 0xcafebabe
|
|
)
|
|
|
|
type HdrFlags uint32
|
|
type SegFlags uint32
|
|
type SecFlags uint32
|
|
|
|
// A HdrType is the Mach-O file type, e.g. an object file, executable, or dynamic library.
|
|
type HdrType uint32
|
|
|
|
const ( // SNAKE_CASE to CamelCase translation from C names
|
|
MhObject HdrType = 1
|
|
MhExecute HdrType = 2
|
|
MhCore HdrType = 4
|
|
MhDylib HdrType = 6
|
|
MhBundle HdrType = 8
|
|
MhDsym HdrType = 0xa
|
|
)
|
|
|
|
var typeStrings = []intName{
|
|
{uint32(MhObject), "Obj"},
|
|
{uint32(MhExecute), "Exec"},
|
|
{uint32(MhDylib), "Dylib"},
|
|
{uint32(MhBundle), "Bundle"},
|
|
{uint32(MhDsym), "Dsym"},
|
|
}
|
|
|
|
func (t HdrType) String() string { return stringName(uint32(t), typeStrings, false) }
|
|
func (t HdrType) GoString() string { return stringName(uint32(t), typeStrings, true) }
|
|
|
|
// A Cpu is a Mach-O cpu type.
|
|
type Cpu uint32
|
|
|
|
const cpuArch64 = 0x01000000
|
|
|
|
const (
|
|
Cpu386 Cpu = 7
|
|
CpuAmd64 Cpu = Cpu386 | cpuArch64
|
|
CpuArm Cpu = 12
|
|
CpuArm64 Cpu = CpuArm | cpuArch64
|
|
CpuPpc Cpu = 18
|
|
CpuPpc64 Cpu = CpuPpc | cpuArch64
|
|
)
|
|
|
|
var cpuStrings = []intName{
|
|
{uint32(Cpu386), "Cpu386"},
|
|
{uint32(CpuAmd64), "CpuAmd64"},
|
|
{uint32(CpuArm), "CpuArm"},
|
|
{uint32(CpuArm64), "CpuArm64"},
|
|
{uint32(CpuPpc), "CpuPpc"},
|
|
{uint32(CpuPpc64), "CpuPpc64"},
|
|
}
|
|
|
|
func (i Cpu) String() string { return stringName(uint32(i), cpuStrings, false) }
|
|
func (i Cpu) GoString() string { return stringName(uint32(i), cpuStrings, true) }
|
|
|
|
// A LoadCmd is a Mach-O load command.
|
|
type LoadCmd uint32
|
|
|
|
func (c LoadCmd) Command() LoadCmd { return c }
|
|
|
|
const ( // SNAKE_CASE to CamelCase translation from C names
|
|
// Note 3 and 8 are obsolete
|
|
LcSegment LoadCmd = 0x1
|
|
LcSymtab LoadCmd = 0x2
|
|
LcThread LoadCmd = 0x4
|
|
LcUnixthread LoadCmd = 0x5 // thread+stack
|
|
LcDysymtab LoadCmd = 0xb
|
|
LcDylib LoadCmd = 0xc // load dylib command
|
|
LcIdDylib LoadCmd = 0xd // dynamically linked shared lib ident
|
|
LcLoadDylinker LoadCmd = 0xe // load a dynamic linker
|
|
LcIdDylinker LoadCmd = 0xf // id dylinker command (not load dylinker command)
|
|
LcSegment64 LoadCmd = 0x19
|
|
LcUuid LoadCmd = 0x1b
|
|
LcCodeSignature LoadCmd = 0x1d
|
|
LcSegmentSplitInfo LoadCmd = 0x1e
|
|
LcRpath LoadCmd = 0x8000001c
|
|
LcEncryptionInfo LoadCmd = 0x21
|
|
LcDyldInfo LoadCmd = 0x22
|
|
LcDyldInfoOnly LoadCmd = 0x80000022
|
|
LcVersionMinMacosx LoadCmd = 0x24
|
|
LcVersionMinIphoneos LoadCmd = 0x25
|
|
LcFunctionStarts LoadCmd = 0x26
|
|
LcDyldEnvironment LoadCmd = 0x27
|
|
LcMain LoadCmd = 0x80000028 // replacement for UnixThread
|
|
LcDataInCode LoadCmd = 0x29 // There are non-instructions in text
|
|
LcSourceVersion LoadCmd = 0x2a // Source version used to build binary
|
|
LcDylibCodeSignDrs LoadCmd = 0x2b
|
|
LcEncryptionInfo64 LoadCmd = 0x2c
|
|
LcVersionMinTvos LoadCmd = 0x2f
|
|
LcVersionMinWatchos LoadCmd = 0x30
|
|
)
|
|
|
|
var cmdStrings = []intName{
|
|
{uint32(LcSegment), "LoadCmdSegment"},
|
|
{uint32(LcThread), "LoadCmdThread"},
|
|
{uint32(LcUnixthread), "LoadCmdUnixThread"},
|
|
{uint32(LcDylib), "LoadCmdDylib"},
|
|
{uint32(LcIdDylib), "LoadCmdIdDylib"},
|
|
{uint32(LcLoadDylinker), "LoadCmdLoadDylinker"},
|
|
{uint32(LcIdDylinker), "LoadCmdIdDylinker"},
|
|
{uint32(LcSegment64), "LoadCmdSegment64"},
|
|
{uint32(LcUuid), "LoadCmdUuid"},
|
|
{uint32(LcRpath), "LoadCmdRpath"},
|
|
{uint32(LcDyldEnvironment), "LoadCmdDyldEnv"},
|
|
{uint32(LcMain), "LoadCmdMain"},
|
|
{uint32(LcDataInCode), "LoadCmdDataInCode"},
|
|
{uint32(LcSourceVersion), "LoadCmdSourceVersion"},
|
|
{uint32(LcDyldInfo), "LoadCmdDyldInfo"},
|
|
{uint32(LcDyldInfoOnly), "LoadCmdDyldInfoOnly"},
|
|
{uint32(LcVersionMinMacosx), "LoadCmdMinOsx"},
|
|
{uint32(LcFunctionStarts), "LoadCmdFunctionStarts"},
|
|
}
|
|
|
|
func (i LoadCmd) String() string { return stringName(uint32(i), cmdStrings, false) }
|
|
func (i LoadCmd) GoString() string { return stringName(uint32(i), cmdStrings, true) }
|
|
|
|
type (
|
|
// A Segment32 is a 32-bit Mach-O segment load command.
|
|
Segment32 struct {
|
|
LoadCmd
|
|
Len uint32
|
|
Name [16]byte
|
|
Addr uint32
|
|
Memsz uint32
|
|
Offset uint32
|
|
Filesz uint32
|
|
Maxprot uint32
|
|
Prot uint32
|
|
Nsect uint32
|
|
Flag SegFlags
|
|
}
|
|
|
|
// A Segment64 is a 64-bit Mach-O segment load command.
|
|
Segment64 struct {
|
|
LoadCmd
|
|
Len uint32
|
|
Name [16]byte
|
|
Addr uint64
|
|
Memsz uint64
|
|
Offset uint64
|
|
Filesz uint64
|
|
Maxprot uint32
|
|
Prot uint32
|
|
Nsect uint32
|
|
Flag SegFlags
|
|
}
|
|
|
|
// A SymtabCmd is a Mach-O symbol table command.
|
|
SymtabCmd struct {
|
|
LoadCmd
|
|
Len uint32
|
|
Symoff uint32
|
|
Nsyms uint32
|
|
Stroff uint32
|
|
Strsize uint32
|
|
}
|
|
|
|
// A DysymtabCmd is a Mach-O dynamic symbol table command.
|
|
DysymtabCmd struct {
|
|
LoadCmd
|
|
Len uint32
|
|
Ilocalsym uint32
|
|
Nlocalsym uint32
|
|
Iextdefsym uint32
|
|
Nextdefsym uint32
|
|
Iundefsym uint32
|
|
Nundefsym uint32
|
|
Tocoffset uint32
|
|
Ntoc uint32
|
|
Modtaboff uint32
|
|
Nmodtab uint32
|
|
Extrefsymoff uint32
|
|
Nextrefsyms uint32
|
|
Indirectsymoff uint32
|
|
Nindirectsyms uint32
|
|
Extreloff uint32
|
|
Nextrel uint32
|
|
Locreloff uint32
|
|
Nlocrel uint32
|
|
}
|
|
|
|
// A DylibCmd is a Mach-O load dynamic library command.
|
|
DylibCmd struct {
|
|
LoadCmd
|
|
Len uint32
|
|
Name uint32
|
|
Time uint32
|
|
CurrentVersion uint32
|
|
CompatVersion uint32
|
|
}
|
|
|
|
// A DylinkerCmd is a Mach-O load dynamic linker or environment command.
|
|
DylinkerCmd struct {
|
|
LoadCmd
|
|
Len uint32
|
|
Name uint32
|
|
}
|
|
|
|
// A RpathCmd is a Mach-O rpath command.
|
|
RpathCmd struct {
|
|
LoadCmd
|
|
Len uint32
|
|
Path uint32
|
|
}
|
|
|
|
// A Thread is a Mach-O thread state command.
|
|
Thread struct {
|
|
LoadCmd
|
|
Len uint32
|
|
Type uint32
|
|
Data []uint32
|
|
}
|
|
|
|
// LC_DYLD_INFO, LC_DYLD_INFO_ONLY
|
|
DyldInfoCmd struct {
|
|
LoadCmd
|
|
Len uint32
|
|
RebaseOff, RebaseLen uint32 // file offset and length; data contains segment indices
|
|
BindOff, BindLen uint32 // file offset and length; data contains segment indices
|
|
WeakBindOff, WeakBindLen uint32 // file offset and length
|
|
LazyBindOff, LazyBindLen uint32 // file offset and length
|
|
ExportOff, ExportLen uint32 // file offset and length
|
|
}
|
|
|
|
// LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO, LC_FUNCTION_STARTS, LC_DATA_IN_CODE, LC_DYLIB_CODE_SIGN_DRS
|
|
LinkEditDataCmd struct {
|
|
LoadCmd
|
|
Len uint32
|
|
DataOff, DataLen uint32 // file offset and length
|
|
}
|
|
|
|
// LC_ENCRYPTION_INFO, LC_ENCRYPTION_INFO_64
|
|
EncryptionInfoCmd struct {
|
|
LoadCmd
|
|
Len uint32
|
|
CryptOff, CryptLen uint32 // file offset and length
|
|
CryptId uint32
|
|
}
|
|
|
|
UuidCmd struct {
|
|
LoadCmd
|
|
Len uint32
|
|
Id [16]byte
|
|
}
|
|
|
|
// TODO Commands below not fully supported yet.
|
|
|
|
EntryPointCmd struct {
|
|
LoadCmd
|
|
Len uint32
|
|
EntryOff uint64 // file offset
|
|
StackSize uint64 // if not zero, initial stack size
|
|
}
|
|
|
|
NoteCmd struct {
|
|
LoadCmd
|
|
Len uint32
|
|
Name [16]byte
|
|
Offset, Filesz uint64 // file offset and length
|
|
}
|
|
)
|
|
|
|
const (
|
|
FlagNoUndefs HdrFlags = 0x1
|
|
FlagIncrLink HdrFlags = 0x2
|
|
FlagDyldLink HdrFlags = 0x4
|
|
FlagBindAtLoad HdrFlags = 0x8
|
|
FlagPrebound HdrFlags = 0x10
|
|
FlagSplitSegs HdrFlags = 0x20
|
|
FlagLazyInit HdrFlags = 0x40
|
|
FlagTwoLevel HdrFlags = 0x80
|
|
FlagForceFlat HdrFlags = 0x100
|
|
FlagNoMultiDefs HdrFlags = 0x200
|
|
FlagNoFixPrebinding HdrFlags = 0x400
|
|
FlagPrebindable HdrFlags = 0x800
|
|
FlagAllModsBound HdrFlags = 0x1000
|
|
FlagSubsectionsViaSymbols HdrFlags = 0x2000
|
|
FlagCanonical HdrFlags = 0x4000
|
|
FlagWeakDefines HdrFlags = 0x8000
|
|
FlagBindsToWeak HdrFlags = 0x10000
|
|
FlagAllowStackExecution HdrFlags = 0x20000
|
|
FlagRootSafe HdrFlags = 0x40000
|
|
FlagSetuidSafe HdrFlags = 0x80000
|
|
FlagNoReexportedDylibs HdrFlags = 0x100000
|
|
FlagPIE HdrFlags = 0x200000
|
|
FlagDeadStrippableDylib HdrFlags = 0x400000
|
|
FlagHasTLVDescriptors HdrFlags = 0x800000
|
|
FlagNoHeapExecution HdrFlags = 0x1000000
|
|
FlagAppExtensionSafe HdrFlags = 0x2000000
|
|
)
|
|
|
|
// A Section32 is a 32-bit Mach-O section header.
|
|
type Section32 struct {
|
|
Name [16]byte
|
|
Seg [16]byte
|
|
Addr uint32
|
|
Size uint32
|
|
Offset uint32
|
|
Align uint32
|
|
Reloff uint32
|
|
Nreloc uint32
|
|
Flags SecFlags
|
|
Reserve1 uint32
|
|
Reserve2 uint32
|
|
}
|
|
|
|
// A Section64 is a 64-bit Mach-O section header.
|
|
type Section64 struct {
|
|
Name [16]byte
|
|
Seg [16]byte
|
|
Addr uint64
|
|
Size uint64
|
|
Offset uint32
|
|
Align uint32
|
|
Reloff uint32
|
|
Nreloc uint32
|
|
Flags SecFlags
|
|
Reserve1 uint32
|
|
Reserve2 uint32
|
|
Reserve3 uint32
|
|
}
|
|
|
|
// An Nlist32 is a Mach-O 32-bit symbol table entry.
|
|
type Nlist32 struct {
|
|
Name uint32
|
|
Type uint8
|
|
Sect uint8
|
|
Desc uint16
|
|
Value uint32
|
|
}
|
|
|
|
// An Nlist64 is a Mach-O 64-bit symbol table entry.
|
|
type Nlist64 struct {
|
|
Name uint32
|
|
Type uint8
|
|
Sect uint8
|
|
Desc uint16
|
|
Value uint64
|
|
}
|
|
|
|
func (n *Nlist64) Put64(b []byte, o binary.ByteOrder) uint32 {
|
|
o.PutUint32(b[0:], n.Name)
|
|
b[4] = byte(n.Type)
|
|
b[5] = byte(n.Sect)
|
|
o.PutUint16(b[6:], n.Desc)
|
|
o.PutUint64(b[8:], n.Value)
|
|
return 8 + 8
|
|
}
|
|
|
|
func (n *Nlist64) Put32(b []byte, o binary.ByteOrder) uint32 {
|
|
o.PutUint32(b[0:], n.Name)
|
|
b[4] = byte(n.Type)
|
|
b[5] = byte(n.Sect)
|
|
o.PutUint16(b[6:], n.Desc)
|
|
o.PutUint32(b[8:], uint32(n.Value))
|
|
return 8 + 4
|
|
}
|
|
|
|
// Regs386 is the Mach-O 386 register structure.
|
|
type Regs386 struct {
|
|
AX uint32
|
|
BX uint32
|
|
CX uint32
|
|
DX uint32
|
|
DI uint32
|
|
SI uint32
|
|
BP uint32
|
|
SP uint32
|
|
SS uint32
|
|
FLAGS uint32
|
|
IP uint32
|
|
CS uint32
|
|
DS uint32
|
|
ES uint32
|
|
FS uint32
|
|
GS uint32
|
|
}
|
|
|
|
// RegsAMD64 is the Mach-O AMD64 register structure.
|
|
type RegsAMD64 struct {
|
|
AX uint64
|
|
BX uint64
|
|
CX uint64
|
|
DX uint64
|
|
DI uint64
|
|
SI uint64
|
|
BP uint64
|
|
SP uint64
|
|
R8 uint64
|
|
R9 uint64
|
|
R10 uint64
|
|
R11 uint64
|
|
R12 uint64
|
|
R13 uint64
|
|
R14 uint64
|
|
R15 uint64
|
|
IP uint64
|
|
FLAGS uint64
|
|
CS uint64
|
|
FS uint64
|
|
GS uint64
|
|
}
|
|
|
|
type intName struct {
|
|
i uint32
|
|
s string
|
|
}
|
|
|
|
func stringName(i uint32, names []intName, goSyntax bool) string {
|
|
for _, n := range names {
|
|
if n.i == i {
|
|
if goSyntax {
|
|
return "macho." + n.s
|
|
}
|
|
return n.s
|
|
}
|
|
}
|
|
return "0x" + strconv.FormatUint(uint64(i), 16)
|
|
}
|