blob: 184ca8375b548e1f474f1392d4aa074b29f037cf [file] [log] [blame]
Russ Coxf0492f42009-08-31 16:48:44 -07001// Copyright 2009 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
Russ Coxf277ebf2009-09-01 16:11:17 -07005// Package elf implements access to ELF object files.
Russ Coxf0492f42009-08-31 16:48:44 -07006package elf
7
8import (
Robert Griesemer1c729592009-12-15 15:27:16 -08009 "bytes"
10 "debug/dwarf"
11 "encoding/binary"
Russ Coxc2049d22011-11-01 22:04:37 -040012 "errors"
Robert Griesemer1c729592009-12-15 15:27:16 -080013 "fmt"
14 "io"
15 "os"
Russ Coxf0492f42009-08-31 16:48:44 -070016)
17
18// TODO: error reporting detail
19
20/*
21 * Internal ELF representation
22 */
23
24// A FileHeader represents an ELF file header.
25type FileHeader struct {
Robert Griesemer1c729592009-12-15 15:27:16 -080026 Class Class
27 Data Data
28 Version Version
29 OSABI OSABI
30 ABIVersion uint8
31 ByteOrder binary.ByteOrder
32 Type Type
33 Machine Machine
Russ Coxf0492f42009-08-31 16:48:44 -070034}
35
36// A File represents an open ELF file.
37type File struct {
Robert Griesemer1c729592009-12-15 15:27:16 -080038 FileHeader
Russ Cox09092a72011-04-27 23:21:03 -040039 Sections []*Section
40 Progs []*Prog
41 closer io.Closer
42 gnuNeed []verneed
43 gnuVersym []byte
Russ Coxf0492f42009-08-31 16:48:44 -070044}
45
46// A SectionHeader represents a single ELF section header.
47type SectionHeader struct {
Robert Griesemer1c729592009-12-15 15:27:16 -080048 Name string
49 Type SectionType
50 Flags SectionFlag
51 Addr uint64
52 Offset uint64
53 Size uint64
54 Link uint32
55 Info uint32
56 Addralign uint64
57 Entsize uint64
Russ Coxf0492f42009-08-31 16:48:44 -070058}
59
60// A Section represents a single section in an ELF file.
61type Section struct {
Robert Griesemer1c729592009-12-15 15:27:16 -080062 SectionHeader
Russ Coxf0492f42009-08-31 16:48:44 -070063
64 // Embed ReaderAt for ReadAt method.
65 // Do not embed SectionReader directly
66 // to avoid having Read and Seek.
67 // If a client wants Read and Seek it must use
68 // Open() to avoid fighting over the seek offset
69 // with other clients.
Robert Griesemer1c729592009-12-15 15:27:16 -080070 io.ReaderAt
71 sr *io.SectionReader
Russ Coxf0492f42009-08-31 16:48:44 -070072}
73
Russ Coxf277ebf2009-09-01 16:11:17 -070074// Data reads and returns the contents of the ELF section.
Russ Coxc2049d22011-11-01 22:04:37 -040075func (s *Section) Data() ([]byte, error) {
Robert Griesemer1c729592009-12-15 15:27:16 -080076 dat := make([]byte, s.sr.Size())
77 n, err := s.sr.ReadAt(dat, 0)
78 return dat[0:n], err
Russ Coxf277ebf2009-09-01 16:11:17 -070079}
80
Russ Cox37499eb2010-12-08 13:53:19 -050081// stringTable reads and returns the string table given by the
82// specified link value.
Russ Coxc2049d22011-11-01 22:04:37 -040083func (f *File) stringTable(link uint32) ([]byte, error) {
Russ Cox37499eb2010-12-08 13:53:19 -050084 if link <= 0 || link >= uint32(len(f.Sections)) {
Russ Coxc2049d22011-11-01 22:04:37 -040085 return nil, errors.New("section has invalid string table link")
Russ Cox37499eb2010-12-08 13:53:19 -050086 }
87 return f.Sections[link].Data()
88}
89
Russ Coxf0492f42009-08-31 16:48:44 -070090// Open returns a new ReadSeeker reading the ELF section.
Robert Griesemer1c729592009-12-15 15:27:16 -080091func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
Russ Coxf0492f42009-08-31 16:48:44 -070092
93// A ProgHeader represents a single ELF program header.
94type ProgHeader struct {
Robert Griesemer1c729592009-12-15 15:27:16 -080095 Type ProgType
96 Flags ProgFlag
Matthew Horsnell932db132011-07-13 12:34:29 -070097 Off uint64
Robert Griesemer1c729592009-12-15 15:27:16 -080098 Vaddr uint64
99 Paddr uint64
100 Filesz uint64
101 Memsz uint64
102 Align uint64
Russ Coxf0492f42009-08-31 16:48:44 -0700103}
104
105// A Prog represents a single ELF program header in an ELF binary.
106type Prog struct {
Robert Griesemer1c729592009-12-15 15:27:16 -0800107 ProgHeader
Russ Coxf0492f42009-08-31 16:48:44 -0700108
109 // Embed ReaderAt for ReadAt method.
110 // Do not embed SectionReader directly
111 // to avoid having Read and Seek.
112 // If a client wants Read and Seek it must use
113 // Open() to avoid fighting over the seek offset
114 // with other clients.
Robert Griesemer1c729592009-12-15 15:27:16 -0800115 io.ReaderAt
116 sr *io.SectionReader
Russ Coxf0492f42009-08-31 16:48:44 -0700117}
118
119// Open returns a new ReadSeeker reading the ELF program body.
Robert Griesemer1c729592009-12-15 15:27:16 -0800120func (p *Prog) Open() io.ReadSeeker { return io.NewSectionReader(p.sr, 0, 1<<63-1) }
Russ Coxf0492f42009-08-31 16:48:44 -0700121
Adam Langley72ec9302009-11-02 12:02:16 -0800122// A Symbol represents an entry in an ELF symbol table section.
123type Symbol struct {
Russ Cox37499eb2010-12-08 13:53:19 -0500124 Name string
Robert Griesemer1c729592009-12-15 15:27:16 -0800125 Info, Other byte
Russ Cox37499eb2010-12-08 13:53:19 -0500126 Section SectionIndex
Robert Griesemer1c729592009-12-15 15:27:16 -0800127 Value, Size uint64
Adam Langley72ec9302009-11-02 12:02:16 -0800128}
Russ Coxf0492f42009-08-31 16:48:44 -0700129
130/*
131 * ELF reader
132 */
133
134type FormatError struct {
Robert Griesemer1c729592009-12-15 15:27:16 -0800135 off int64
136 msg string
137 val interface{}
Russ Coxf0492f42009-08-31 16:48:44 -0700138}
139
Russ Coxc2049d22011-11-01 22:04:37 -0400140func (e *FormatError) Error() string {
Robert Griesemer1c729592009-12-15 15:27:16 -0800141 msg := e.msg
Russ Coxf0492f42009-08-31 16:48:44 -0700142 if e.val != nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800143 msg += fmt.Sprintf(" '%v' ", e.val)
Russ Coxf0492f42009-08-31 16:48:44 -0700144 }
Robert Griesemer1c729592009-12-15 15:27:16 -0800145 msg += fmt.Sprintf("in record at byte %#x", e.off)
146 return msg
Russ Coxf0492f42009-08-31 16:48:44 -0700147}
148
149// Open opens the named file using os.Open and prepares it for use as an ELF binary.
Russ Coxc2049d22011-11-01 22:04:37 -0400150func Open(name string) (*File, error) {
Rob Pike8a90fd32011-04-04 23:42:14 -0700151 f, err := os.Open(name)
Russ Coxf0492f42009-08-31 16:48:44 -0700152 if err != nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800153 return nil, err
Russ Coxf0492f42009-08-31 16:48:44 -0700154 }
Robert Griesemer1c729592009-12-15 15:27:16 -0800155 ff, err := NewFile(f)
Russ Coxf0492f42009-08-31 16:48:44 -0700156 if err != nil {
Robert Griesemer1c729592009-12-15 15:27:16 -0800157 f.Close()
158 return nil, err
Russ Coxf0492f42009-08-31 16:48:44 -0700159 }
Robert Griesemer1c729592009-12-15 15:27:16 -0800160 ff.closer = f
161 return ff, nil
Russ Coxf0492f42009-08-31 16:48:44 -0700162}
163
164// Close closes the File.
165// If the File was created using NewFile directly instead of Open,
166// Close has no effect.
Russ Coxc2049d22011-11-01 22:04:37 -0400167func (f *File) Close() error {
168 var err error
Russ Coxf0492f42009-08-31 16:48:44 -0700169 if f.closer != nil {
Robert Griesemer1c729592009-12-15 15:27:16 -0800170 err = f.closer.Close()
171 f.closer = nil
Russ Coxf0492f42009-08-31 16:48:44 -0700172 }
Robert Griesemer1c729592009-12-15 15:27:16 -0800173 return err
Russ Coxf0492f42009-08-31 16:48:44 -0700174}
175
Russ Cox37499eb2010-12-08 13:53:19 -0500176// SectionByType returns the first section in f with the
177// given type, or nil if there is no such section.
178func (f *File) SectionByType(typ SectionType) *Section {
179 for _, s := range f.Sections {
180 if s.Type == typ {
181 return s
182 }
183 }
184 return nil
185}
186
Evan Shawd7701052010-04-11 14:49:44 -0700187// NewFile creates a new File for accessing an ELF binary in an underlying reader.
Russ Coxf0492f42009-08-31 16:48:44 -0700188// The ELF binary is expected to start at position 0 in the ReaderAt.
Russ Coxc2049d22011-11-01 22:04:37 -0400189func NewFile(r io.ReaderAt) (*File, error) {
Robert Griesemer1c729592009-12-15 15:27:16 -0800190 sr := io.NewSectionReader(r, 0, 1<<63-1)
Russ Coxf0492f42009-08-31 16:48:44 -0700191 // Read and decode ELF identifier
Robert Griesemer1c729592009-12-15 15:27:16 -0800192 var ident [16]uint8
Russ Coxbb84f4b2010-05-27 14:51:47 -0700193 if _, err := r.ReadAt(ident[0:], 0); err != nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800194 return nil, err
Russ Coxf0492f42009-08-31 16:48:44 -0700195 }
196 if ident[0] != '\x7f' || ident[1] != 'E' || ident[2] != 'L' || ident[3] != 'F' {
Robert Griesemer40621d52009-11-09 12:07:39 -0800197 return nil, &FormatError{0, "bad magic number", ident[0:4]}
Russ Coxf0492f42009-08-31 16:48:44 -0700198 }
199
Robert Griesemer1c729592009-12-15 15:27:16 -0800200 f := new(File)
201 f.Class = Class(ident[EI_CLASS])
Russ Coxf0492f42009-08-31 16:48:44 -0700202 switch f.Class {
203 case ELFCLASS32:
204 case ELFCLASS64:
Russ Coxd2829fa2009-10-27 22:47:54 -0700205 // ok
Russ Coxf0492f42009-08-31 16:48:44 -0700206 default:
Robert Griesemer40621d52009-11-09 12:07:39 -0800207 return nil, &FormatError{0, "unknown ELF class", f.Class}
Russ Coxf0492f42009-08-31 16:48:44 -0700208 }
209
Robert Griesemer1c729592009-12-15 15:27:16 -0800210 f.Data = Data(ident[EI_DATA])
Russ Coxf0492f42009-08-31 16:48:44 -0700211 switch f.Data {
212 case ELFDATA2LSB:
Robert Griesemer40621d52009-11-09 12:07:39 -0800213 f.ByteOrder = binary.LittleEndian
Russ Coxf0492f42009-08-31 16:48:44 -0700214 case ELFDATA2MSB:
Robert Griesemer40621d52009-11-09 12:07:39 -0800215 f.ByteOrder = binary.BigEndian
Russ Coxf0492f42009-08-31 16:48:44 -0700216 default:
Robert Griesemer40621d52009-11-09 12:07:39 -0800217 return nil, &FormatError{0, "unknown ELF data encoding", f.Data}
Russ Coxf0492f42009-08-31 16:48:44 -0700218 }
219
Robert Griesemer1c729592009-12-15 15:27:16 -0800220 f.Version = Version(ident[EI_VERSION])
Russ Coxf0492f42009-08-31 16:48:44 -0700221 if f.Version != EV_CURRENT {
Robert Griesemer40621d52009-11-09 12:07:39 -0800222 return nil, &FormatError{0, "unknown ELF version", f.Version}
Russ Coxf0492f42009-08-31 16:48:44 -0700223 }
224
Robert Griesemer1c729592009-12-15 15:27:16 -0800225 f.OSABI = OSABI(ident[EI_OSABI])
226 f.ABIVersion = ident[EI_ABIVERSION]
Russ Coxf0492f42009-08-31 16:48:44 -0700227
228 // Read ELF file header
Matthew Horsnell932db132011-07-13 12:34:29 -0700229 var phoff int64
230 var phentsize, phnum int
Robert Griesemer1c729592009-12-15 15:27:16 -0800231 var shoff int64
232 var shentsize, shnum, shstrndx int
233 shstrndx = -1
Russ Coxf0492f42009-08-31 16:48:44 -0700234 switch f.Class {
235 case ELFCLASS32:
Robert Griesemer1c729592009-12-15 15:27:16 -0800236 hdr := new(Header32)
Brad Fitzpatrick2be13a82011-04-04 13:53:52 -0700237 sr.Seek(0, os.SEEK_SET)
Russ Coxf0492f42009-08-31 16:48:44 -0700238 if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800239 return nil, err
Russ Coxf0492f42009-08-31 16:48:44 -0700240 }
Robert Griesemer1c729592009-12-15 15:27:16 -0800241 f.Type = Type(hdr.Type)
242 f.Machine = Machine(hdr.Machine)
Russ Coxf0492f42009-08-31 16:48:44 -0700243 if v := Version(hdr.Version); v != f.Version {
Robert Griesemer40621d52009-11-09 12:07:39 -0800244 return nil, &FormatError{0, "mismatched ELF version", v}
Russ Coxf0492f42009-08-31 16:48:44 -0700245 }
Matthew Horsnell932db132011-07-13 12:34:29 -0700246 phoff = int64(hdr.Phoff)
247 phentsize = int(hdr.Phentsize)
248 phnum = int(hdr.Phnum)
Robert Griesemer1c729592009-12-15 15:27:16 -0800249 shoff = int64(hdr.Shoff)
250 shentsize = int(hdr.Shentsize)
251 shnum = int(hdr.Shnum)
252 shstrndx = int(hdr.Shstrndx)
Russ Coxf0492f42009-08-31 16:48:44 -0700253 case ELFCLASS64:
Robert Griesemer1c729592009-12-15 15:27:16 -0800254 hdr := new(Header64)
Brad Fitzpatrick2be13a82011-04-04 13:53:52 -0700255 sr.Seek(0, os.SEEK_SET)
Russ Coxf0492f42009-08-31 16:48:44 -0700256 if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800257 return nil, err
Russ Coxf0492f42009-08-31 16:48:44 -0700258 }
Robert Griesemer1c729592009-12-15 15:27:16 -0800259 f.Type = Type(hdr.Type)
260 f.Machine = Machine(hdr.Machine)
Russ Coxf0492f42009-08-31 16:48:44 -0700261 if v := Version(hdr.Version); v != f.Version {
Robert Griesemer40621d52009-11-09 12:07:39 -0800262 return nil, &FormatError{0, "mismatched ELF version", v}
Russ Coxf0492f42009-08-31 16:48:44 -0700263 }
Matthew Horsnell932db132011-07-13 12:34:29 -0700264 phoff = int64(hdr.Phoff)
265 phentsize = int(hdr.Phentsize)
266 phnum = int(hdr.Phnum)
Robert Griesemer1c729592009-12-15 15:27:16 -0800267 shoff = int64(hdr.Shoff)
268 shentsize = int(hdr.Shentsize)
269 shnum = int(hdr.Shnum)
270 shstrndx = int(hdr.Shstrndx)
Russ Coxf0492f42009-08-31 16:48:44 -0700271 }
272 if shstrndx < 0 || shstrndx >= shnum {
Robert Griesemer40621d52009-11-09 12:07:39 -0800273 return nil, &FormatError{0, "invalid ELF shstrndx", shstrndx}
Russ Coxf0492f42009-08-31 16:48:44 -0700274 }
275
276 // Read program headers
Matthew Horsnell932db132011-07-13 12:34:29 -0700277 f.Progs = make([]*Prog, phnum)
278 for i := 0; i < phnum; i++ {
279 off := phoff + int64(i)*int64(phentsize)
280 sr.Seek(off, os.SEEK_SET)
281 p := new(Prog)
282 switch f.Class {
283 case ELFCLASS32:
284 ph := new(Prog32)
285 if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
286 return nil, err
287 }
288 p.ProgHeader = ProgHeader{
289 Type: ProgType(ph.Type),
290 Flags: ProgFlag(ph.Flags),
291 Off: uint64(ph.Off),
292 Vaddr: uint64(ph.Vaddr),
293 Paddr: uint64(ph.Paddr),
294 Filesz: uint64(ph.Filesz),
295 Memsz: uint64(ph.Memsz),
296 Align: uint64(ph.Align),
297 }
298 case ELFCLASS64:
299 ph := new(Prog64)
300 if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
301 return nil, err
302 }
303 p.ProgHeader = ProgHeader{
304 Type: ProgType(ph.Type),
305 Flags: ProgFlag(ph.Flags),
306 Off: uint64(ph.Off),
307 Vaddr: uint64(ph.Vaddr),
308 Paddr: uint64(ph.Paddr),
309 Filesz: uint64(ph.Filesz),
310 Memsz: uint64(ph.Memsz),
311 Align: uint64(ph.Align),
312 }
313 }
314 p.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz))
315 p.ReaderAt = p.sr
316 f.Progs[i] = p
317 }
Russ Coxf0492f42009-08-31 16:48:44 -0700318
319 // Read section headers
Robert Griesemer1c729592009-12-15 15:27:16 -0800320 f.Sections = make([]*Section, shnum)
321 names := make([]uint32, shnum)
Russ Coxf0492f42009-08-31 16:48:44 -0700322 for i := 0; i < shnum; i++ {
Robert Griesemer1c729592009-12-15 15:27:16 -0800323 off := shoff + int64(i)*int64(shentsize)
Brad Fitzpatrick2be13a82011-04-04 13:53:52 -0700324 sr.Seek(off, os.SEEK_SET)
Robert Griesemer1c729592009-12-15 15:27:16 -0800325 s := new(Section)
Russ Coxf0492f42009-08-31 16:48:44 -0700326 switch f.Class {
327 case ELFCLASS32:
Robert Griesemer1c729592009-12-15 15:27:16 -0800328 sh := new(Section32)
Russ Coxf0492f42009-08-31 16:48:44 -0700329 if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800330 return nil, err
Russ Coxf0492f42009-08-31 16:48:44 -0700331 }
Robert Griesemer1c729592009-12-15 15:27:16 -0800332 names[i] = sh.Name
Russ Coxf0492f42009-08-31 16:48:44 -0700333 s.SectionHeader = SectionHeader{
Robert Griesemerf44fa9b2010-03-02 13:46:51 -0800334 Type: SectionType(sh.Type),
335 Flags: SectionFlag(sh.Flags),
336 Addr: uint64(sh.Addr),
337 Offset: uint64(sh.Off),
338 Size: uint64(sh.Size),
339 Link: uint32(sh.Link),
340 Info: uint32(sh.Info),
Russ Coxf0492f42009-08-31 16:48:44 -0700341 Addralign: uint64(sh.Addralign),
Robert Griesemerf44fa9b2010-03-02 13:46:51 -0800342 Entsize: uint64(sh.Entsize),
Robert Griesemer1c729592009-12-15 15:27:16 -0800343 }
Russ Coxf0492f42009-08-31 16:48:44 -0700344 case ELFCLASS64:
Robert Griesemer1c729592009-12-15 15:27:16 -0800345 sh := new(Section64)
Russ Coxf0492f42009-08-31 16:48:44 -0700346 if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800347 return nil, err
Russ Coxf0492f42009-08-31 16:48:44 -0700348 }
Robert Griesemer1c729592009-12-15 15:27:16 -0800349 names[i] = sh.Name
Russ Coxf0492f42009-08-31 16:48:44 -0700350 s.SectionHeader = SectionHeader{
Robert Griesemerf44fa9b2010-03-02 13:46:51 -0800351 Type: SectionType(sh.Type),
352 Flags: SectionFlag(sh.Flags),
353 Offset: uint64(sh.Off),
354 Size: uint64(sh.Size),
355 Addr: uint64(sh.Addr),
356 Link: uint32(sh.Link),
357 Info: uint32(sh.Info),
Russ Coxf0492f42009-08-31 16:48:44 -0700358 Addralign: uint64(sh.Addralign),
Robert Griesemerf44fa9b2010-03-02 13:46:51 -0800359 Entsize: uint64(sh.Entsize),
Robert Griesemer1c729592009-12-15 15:27:16 -0800360 }
Russ Coxf0492f42009-08-31 16:48:44 -0700361 }
Robert Griesemer1c729592009-12-15 15:27:16 -0800362 s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Size))
363 s.ReaderAt = s.sr
364 f.Sections[i] = s
Russ Coxf0492f42009-08-31 16:48:44 -0700365 }
366
367 // Load section header string table.
Russ Cox37499eb2010-12-08 13:53:19 -0500368 shstrtab, err := f.Sections[shstrndx].Data()
369 if err != nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800370 return nil, err
Russ Coxf0492f42009-08-31 16:48:44 -0700371 }
372 for i, s := range f.Sections {
Robert Griesemer1c729592009-12-15 15:27:16 -0800373 var ok bool
374 s.Name, ok = getString(shstrtab, int(names[i]))
Russ Coxf0492f42009-08-31 16:48:44 -0700375 if !ok {
Robert Griesemerbaba2922009-11-09 21:13:17 -0800376 return nil, &FormatError{shoff + int64(i*shentsize), "bad section name index", names[i]}
Russ Coxf0492f42009-08-31 16:48:44 -0700377 }
378 }
379
Robert Griesemer1c729592009-12-15 15:27:16 -0800380 return f, nil
Russ Coxf0492f42009-08-31 16:48:44 -0700381}
382
Russ Cox37499eb2010-12-08 13:53:19 -0500383// getSymbols returns a slice of Symbols from parsing the symbol table
Russ Cox09092a72011-04-27 23:21:03 -0400384// with the given type, along with the associated string table.
Russ Coxc2049d22011-11-01 22:04:37 -0400385func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, error) {
Adam Langley72ec9302009-11-02 12:02:16 -0800386 switch f.Class {
387 case ELFCLASS64:
Russ Cox37499eb2010-12-08 13:53:19 -0500388 return f.getSymbols64(typ)
389
390 case ELFCLASS32:
391 return f.getSymbols32(typ)
Adam Langley72ec9302009-11-02 12:02:16 -0800392 }
393
Russ Coxc2049d22011-11-01 22:04:37 -0400394 return nil, nil, errors.New("not implemented")
Adam Langley72ec9302009-11-02 12:02:16 -0800395}
396
Russ Coxc2049d22011-11-01 22:04:37 -0400397func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) {
Russ Cox37499eb2010-12-08 13:53:19 -0500398 symtabSection := f.SectionByType(typ)
399 if symtabSection == nil {
Russ Coxc2049d22011-11-01 22:04:37 -0400400 return nil, nil, errors.New("no symbol section")
Adam Langley72ec9302009-11-02 12:02:16 -0800401 }
402
Russ Cox37499eb2010-12-08 13:53:19 -0500403 data, err := symtabSection.Data()
404 if err != nil {
Russ Coxc2049d22011-11-01 22:04:37 -0400405 return nil, nil, errors.New("cannot load symbol section")
Russ Cox37499eb2010-12-08 13:53:19 -0500406 }
407 symtab := bytes.NewBuffer(data)
408 if symtab.Len()%Sym32Size != 0 {
Russ Coxc2049d22011-11-01 22:04:37 -0400409 return nil, nil, errors.New("length of symbol section is not a multiple of SymSize")
Russ Cox37499eb2010-12-08 13:53:19 -0500410 }
411
412 strdata, err := f.stringTable(symtabSection.Link)
413 if err != nil {
Russ Coxc2049d22011-11-01 22:04:37 -0400414 return nil, nil, errors.New("cannot load string table section")
Russ Cox37499eb2010-12-08 13:53:19 -0500415 }
416
417 // The first entry is all zeros.
418 var skip [Sym32Size]byte
419 symtab.Read(skip[0:])
420
421 symbols := make([]Symbol, symtab.Len()/Sym32Size)
422
423 i := 0
424 var sym Sym32
425 for symtab.Len() > 0 {
426 binary.Read(symtab, f.ByteOrder, &sym)
427 str, _ := getString(strdata, int(sym.Name))
428 symbols[i].Name = str
429 symbols[i].Info = sym.Info
430 symbols[i].Other = sym.Other
431 symbols[i].Section = SectionIndex(sym.Shndx)
432 symbols[i].Value = uint64(sym.Value)
433 symbols[i].Size = uint64(sym.Size)
434 i++
435 }
436
Russ Cox09092a72011-04-27 23:21:03 -0400437 return symbols, strdata, nil
Russ Cox37499eb2010-12-08 13:53:19 -0500438}
439
Russ Coxc2049d22011-11-01 22:04:37 -0400440func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) {
Russ Cox37499eb2010-12-08 13:53:19 -0500441 symtabSection := f.SectionByType(typ)
Adam Langley72ec9302009-11-02 12:02:16 -0800442 if symtabSection == nil {
Russ Coxc2049d22011-11-01 22:04:37 -0400443 return nil, nil, errors.New("no symbol section")
Adam Langley72ec9302009-11-02 12:02:16 -0800444 }
445
Robert Griesemer1c729592009-12-15 15:27:16 -0800446 data, err := symtabSection.Data()
Adam Langley72ec9302009-11-02 12:02:16 -0800447 if err != nil {
Russ Coxc2049d22011-11-01 22:04:37 -0400448 return nil, nil, errors.New("cannot load symbol section")
Adam Langley72ec9302009-11-02 12:02:16 -0800449 }
Robert Griesemer1c729592009-12-15 15:27:16 -0800450 symtab := bytes.NewBuffer(data)
Robert Griesemerbaba2922009-11-09 21:13:17 -0800451 if symtab.Len()%Sym64Size != 0 {
Russ Coxc2049d22011-11-01 22:04:37 -0400452 return nil, nil, errors.New("length of symbol section is not a multiple of Sym64Size")
Adam Langley72ec9302009-11-02 12:02:16 -0800453 }
454
Russ Cox37499eb2010-12-08 13:53:19 -0500455 strdata, err := f.stringTable(symtabSection.Link)
456 if err != nil {
Russ Coxc2049d22011-11-01 22:04:37 -0400457 return nil, nil, errors.New("cannot load string table section")
Russ Cox37499eb2010-12-08 13:53:19 -0500458 }
459
Adam Langley72ec9302009-11-02 12:02:16 -0800460 // The first entry is all zeros.
Robert Griesemer1c729592009-12-15 15:27:16 -0800461 var skip [Sym64Size]byte
462 symtab.Read(skip[0:])
Adam Langley72ec9302009-11-02 12:02:16 -0800463
Robert Griesemer1c729592009-12-15 15:27:16 -0800464 symbols := make([]Symbol, symtab.Len()/Sym64Size)
Adam Langley72ec9302009-11-02 12:02:16 -0800465
Robert Griesemer1c729592009-12-15 15:27:16 -0800466 i := 0
467 var sym Sym64
Adam Langley72ec9302009-11-02 12:02:16 -0800468 for symtab.Len() > 0 {
Robert Griesemer1c729592009-12-15 15:27:16 -0800469 binary.Read(symtab, f.ByteOrder, &sym)
Russ Cox37499eb2010-12-08 13:53:19 -0500470 str, _ := getString(strdata, int(sym.Name))
471 symbols[i].Name = str
Robert Griesemer1c729592009-12-15 15:27:16 -0800472 symbols[i].Info = sym.Info
473 symbols[i].Other = sym.Other
Russ Cox37499eb2010-12-08 13:53:19 -0500474 symbols[i].Section = SectionIndex(sym.Shndx)
Robert Griesemer1c729592009-12-15 15:27:16 -0800475 symbols[i].Value = sym.Value
476 symbols[i].Size = sym.Size
477 i++
Adam Langley72ec9302009-11-02 12:02:16 -0800478 }
479
Russ Cox09092a72011-04-27 23:21:03 -0400480 return symbols, strdata, nil
Adam Langley72ec9302009-11-02 12:02:16 -0800481}
482
Russ Coxf0492f42009-08-31 16:48:44 -0700483// getString extracts a string from an ELF string table.
484func getString(section []byte, start int) (string, bool) {
485 if start < 0 || start >= len(section) {
Robert Griesemer40621d52009-11-09 12:07:39 -0800486 return "", false
Russ Coxf0492f42009-08-31 16:48:44 -0700487 }
488
489 for end := start; end < len(section); end++ {
490 if section[end] == 0 {
Robert Griesemer40621d52009-11-09 12:07:39 -0800491 return string(section[start:end]), true
Russ Coxf0492f42009-08-31 16:48:44 -0700492 }
493 }
Robert Griesemer1c729592009-12-15 15:27:16 -0800494 return "", false
Russ Coxf0492f42009-08-31 16:48:44 -0700495}
496
497// Section returns a section with the given name, or nil if no such
498// section exists.
499func (f *File) Section(name string) *Section {
500 for _, s := range f.Sections {
501 if s.Name == name {
Robert Griesemer40621d52009-11-09 12:07:39 -0800502 return s
Russ Coxf0492f42009-08-31 16:48:44 -0700503 }
504 }
Robert Griesemer1c729592009-12-15 15:27:16 -0800505 return nil
Russ Coxf0492f42009-08-31 16:48:44 -0700506}
Russ Cox92f773d2009-09-18 11:50:24 -0700507
Adam Langley72ec9302009-11-02 12:02:16 -0800508// applyRelocations applies relocations to dst. rels is a relocations section
509// in RELA format.
Russ Coxc2049d22011-11-01 22:04:37 -0400510func (f *File) applyRelocations(dst []byte, rels []byte) error {
Adam Langley72ec9302009-11-02 12:02:16 -0800511 if f.Class == ELFCLASS64 && f.Machine == EM_X86_64 {
Robert Griesemer40621d52009-11-09 12:07:39 -0800512 return f.applyRelocationsAMD64(dst, rels)
Adam Langley72ec9302009-11-02 12:02:16 -0800513 }
514
Russ Coxc2049d22011-11-01 22:04:37 -0400515 return errors.New("not implemented")
Adam Langley72ec9302009-11-02 12:02:16 -0800516}
517
Russ Coxc2049d22011-11-01 22:04:37 -0400518func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
Robert Griesemerbaba2922009-11-09 21:13:17 -0800519 if len(rels)%Sym64Size != 0 {
Russ Coxc2049d22011-11-01 22:04:37 -0400520 return errors.New("length of relocation section is not a multiple of Sym64Size")
Adam Langley72ec9302009-11-02 12:02:16 -0800521 }
522
Russ Cox09092a72011-04-27 23:21:03 -0400523 symbols, _, err := f.getSymbols(SHT_SYMTAB)
Adam Langley72ec9302009-11-02 12:02:16 -0800524 if err != nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800525 return err
Adam Langley72ec9302009-11-02 12:02:16 -0800526 }
527
Robert Griesemer1c729592009-12-15 15:27:16 -0800528 b := bytes.NewBuffer(rels)
529 var rela Rela64
Adam Langley72ec9302009-11-02 12:02:16 -0800530
531 for b.Len() > 0 {
Robert Griesemer1c729592009-12-15 15:27:16 -0800532 binary.Read(b, f.ByteOrder, &rela)
533 symNo := rela.Info >> 32
534 t := R_X86_64(rela.Info & 0xffff)
Adam Langley72ec9302009-11-02 12:02:16 -0800535
536 if symNo >= uint64(len(symbols)) {
Robert Griesemer40621d52009-11-09 12:07:39 -0800537 continue
Adam Langley72ec9302009-11-02 12:02:16 -0800538 }
Robert Griesemer1c729592009-12-15 15:27:16 -0800539 sym := &symbols[symNo]
Robert Griesemerbaba2922009-11-09 21:13:17 -0800540 if SymType(sym.Info&0xf) != STT_SECTION {
Adam Langley72ec9302009-11-02 12:02:16 -0800541 // We don't handle non-section relocations for now.
Robert Griesemer40621d52009-11-09 12:07:39 -0800542 continue
Adam Langley72ec9302009-11-02 12:02:16 -0800543 }
544
545 switch t {
546 case R_X86_64_64:
Robert Griesemerbaba2922009-11-09 21:13:17 -0800547 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
Robert Griesemer40621d52009-11-09 12:07:39 -0800548 continue
Adam Langley72ec9302009-11-02 12:02:16 -0800549 }
Robert Griesemer1c729592009-12-15 15:27:16 -0800550 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
Adam Langley72ec9302009-11-02 12:02:16 -0800551 case R_X86_64_32:
Robert Griesemerbaba2922009-11-09 21:13:17 -0800552 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
Robert Griesemer40621d52009-11-09 12:07:39 -0800553 continue
Adam Langley72ec9302009-11-02 12:02:16 -0800554 }
Robert Griesemer1c729592009-12-15 15:27:16 -0800555 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
Adam Langley72ec9302009-11-02 12:02:16 -0800556 }
557 }
558
Robert Griesemer1c729592009-12-15 15:27:16 -0800559 return nil
Adam Langley72ec9302009-11-02 12:02:16 -0800560}
561
Russ Coxc2049d22011-11-01 22:04:37 -0400562func (f *File) DWARF() (*dwarf.Data, error) {
Russ Cox92f773d2009-09-18 11:50:24 -0700563 // There are many other DWARF sections, but these
564 // are the required ones, and the debug/dwarf package
565 // does not use the others, so don't bother loading them.
Robert Griesemer1c729592009-12-15 15:27:16 -0800566 var names = [...]string{"abbrev", "info", "str"}
567 var dat [len(names)][]byte
Russ Cox92f773d2009-09-18 11:50:24 -0700568 for i, name := range names {
Robert Griesemer1c729592009-12-15 15:27:16 -0800569 name = ".debug_" + name
570 s := f.Section(name)
Russ Cox92f773d2009-09-18 11:50:24 -0700571 if s == nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800572 continue
Russ Cox92f773d2009-09-18 11:50:24 -0700573 }
Robert Griesemer1c729592009-12-15 15:27:16 -0800574 b, err := s.Data()
Russ Cox92f773d2009-09-18 11:50:24 -0700575 if err != nil && uint64(len(b)) < s.Size {
Robert Griesemer40621d52009-11-09 12:07:39 -0800576 return nil, err
Russ Cox92f773d2009-09-18 11:50:24 -0700577 }
Robert Griesemer1c729592009-12-15 15:27:16 -0800578 dat[i] = b
Russ Cox92f773d2009-09-18 11:50:24 -0700579 }
580
Adam Langley72ec9302009-11-02 12:02:16 -0800581 // If there's a relocation table for .debug_info, we have to process it
582 // now otherwise the data in .debug_info is invalid for x86-64 objects.
Robert Griesemer1c729592009-12-15 15:27:16 -0800583 rela := f.Section(".rela.debug_info")
Adam Langley72ec9302009-11-02 12:02:16 -0800584 if rela != nil && rela.Type == SHT_RELA && f.Machine == EM_X86_64 {
Robert Griesemer1c729592009-12-15 15:27:16 -0800585 data, err := rela.Data()
Adam Langley72ec9302009-11-02 12:02:16 -0800586 if err != nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800587 return nil, err
Adam Langley72ec9302009-11-02 12:02:16 -0800588 }
Robert Griesemer1c729592009-12-15 15:27:16 -0800589 err = f.applyRelocations(dat[1], data)
Adam Langley72ec9302009-11-02 12:02:16 -0800590 if err != nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800591 return nil, err
Adam Langley72ec9302009-11-02 12:02:16 -0800592 }
593 }
594
Robert Griesemer1c729592009-12-15 15:27:16 -0800595 abbrev, info, str := dat[0], dat[1], dat[2]
596 return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
Russ Cox92f773d2009-09-18 11:50:24 -0700597}
Russ Cox37499eb2010-12-08 13:53:19 -0500598
Russ Cox99680902011-06-13 14:43:54 -0400599// Symbols returns the symbol table for f.
Russ Coxc2049d22011-11-01 22:04:37 -0400600func (f *File) Symbols() ([]Symbol, error) {
Russ Cox99680902011-06-13 14:43:54 -0400601 sym, _, err := f.getSymbols(SHT_SYMTAB)
602 return sym, err
603}
604
Russ Cox09092a72011-04-27 23:21:03 -0400605type ImportedSymbol struct {
606 Name string
607 Version string
608 Library string
609}
610
Russ Cox37499eb2010-12-08 13:53:19 -0500611// ImportedSymbols returns the names of all symbols
612// referred to by the binary f that are expected to be
613// satisfied by other libraries at dynamic load time.
614// It does not return weak symbols.
Russ Coxc2049d22011-11-01 22:04:37 -0400615func (f *File) ImportedSymbols() ([]ImportedSymbol, error) {
Russ Cox09092a72011-04-27 23:21:03 -0400616 sym, str, err := f.getSymbols(SHT_DYNSYM)
Russ Cox37499eb2010-12-08 13:53:19 -0500617 if err != nil {
618 return nil, err
619 }
Russ Cox09092a72011-04-27 23:21:03 -0400620 f.gnuVersionInit(str)
621 var all []ImportedSymbol
622 for i, s := range sym {
Russ Cox37499eb2010-12-08 13:53:19 -0500623 if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF {
Russ Cox09092a72011-04-27 23:21:03 -0400624 all = append(all, ImportedSymbol{Name: s.Name})
625 f.gnuVersion(i, &all[len(all)-1])
Russ Cox37499eb2010-12-08 13:53:19 -0500626 }
627 }
628 return all, nil
629}
630
Russ Cox09092a72011-04-27 23:21:03 -0400631type verneed struct {
632 File string
633 Name string
634}
635
636// gnuVersionInit parses the GNU version tables
637// for use by calls to gnuVersion.
638func (f *File) gnuVersionInit(str []byte) {
639 // Accumulate verneed information.
640 vn := f.SectionByType(SHT_GNU_VERNEED)
641 if vn == nil {
642 return
643 }
644 d, _ := vn.Data()
645
646 var need []verneed
647 i := 0
648 for {
649 if i+16 > len(d) {
650 break
651 }
652 vers := f.ByteOrder.Uint16(d[i : i+2])
653 if vers != 1 {
654 break
655 }
656 cnt := f.ByteOrder.Uint16(d[i+2 : i+4])
657 fileoff := f.ByteOrder.Uint32(d[i+4 : i+8])
658 aux := f.ByteOrder.Uint32(d[i+8 : i+12])
659 next := f.ByteOrder.Uint32(d[i+12 : i+16])
660 file, _ := getString(str, int(fileoff))
661
662 var name string
663 j := i + int(aux)
664 for c := 0; c < int(cnt); c++ {
665 if j+16 > len(d) {
666 break
667 }
668 // hash := f.ByteOrder.Uint32(d[j:j+4])
669 // flags := f.ByteOrder.Uint16(d[j+4:j+6])
670 other := f.ByteOrder.Uint16(d[j+6 : j+8])
671 nameoff := f.ByteOrder.Uint32(d[j+8 : j+12])
672 next := f.ByteOrder.Uint32(d[j+12 : j+16])
673 name, _ = getString(str, int(nameoff))
674 ndx := int(other)
675 if ndx >= len(need) {
676 a := make([]verneed, 2*(ndx+1))
677 copy(a, need)
678 need = a
679 }
680
681 need[ndx] = verneed{file, name}
682 if next == 0 {
683 break
684 }
685 j += int(next)
686 }
687
688 if next == 0 {
689 break
690 }
691 i += int(next)
692 }
693
694 // Versym parallels symbol table, indexing into verneed.
695 vs := f.SectionByType(SHT_GNU_VERSYM)
696 if vs == nil {
697 return
698 }
699 d, _ = vs.Data()
700
701 f.gnuNeed = need
702 f.gnuVersym = d
703}
704
705// gnuVersion adds Library and Version information to sym,
706// which came from offset i of the symbol table.
707func (f *File) gnuVersion(i int, sym *ImportedSymbol) {
708 // Each entry is two bytes; skip undef entry at beginning.
709 i = (i + 1) * 2
710 if i >= len(f.gnuVersym) {
711 return
712 }
713 j := int(f.ByteOrder.Uint16(f.gnuVersym[i:]))
714 if j < 2 || j >= len(f.gnuNeed) {
715 return
716 }
717 n := &f.gnuNeed[j]
718 sym.Library = n.File
719 sym.Version = n.Name
720}
721
Russ Cox37499eb2010-12-08 13:53:19 -0500722// ImportedLibraries returns the names of all libraries
723// referred to by the binary f that are expected to be
724// linked with the binary at dynamic link time.
Russ Coxc2049d22011-11-01 22:04:37 -0400725func (f *File) ImportedLibraries() ([]string, error) {
Russ Cox37499eb2010-12-08 13:53:19 -0500726 ds := f.SectionByType(SHT_DYNAMIC)
727 if ds == nil {
728 // not dynamic, so no libraries
729 return nil, nil
730 }
731 d, err := ds.Data()
732 if err != nil {
733 return nil, err
734 }
735 str, err := f.stringTable(ds.Link)
736 if err != nil {
737 return nil, err
738 }
739 var all []string
740 for len(d) > 0 {
741 var tag DynTag
742 var value uint64
743 switch f.Class {
744 case ELFCLASS32:
745 tag = DynTag(f.ByteOrder.Uint32(d[0:4]))
746 value = uint64(f.ByteOrder.Uint32(d[4:8]))
747 d = d[8:]
748 case ELFCLASS64:
749 tag = DynTag(f.ByteOrder.Uint64(d[0:8]))
750 value = f.ByteOrder.Uint64(d[8:16])
751 d = d[16:]
752 }
753 if tag == DT_NEEDED {
754 s, ok := getString(str, int(value))
755 if ok {
756 all = append(all, s)
757 }
758 }
759 }
760
761 return all, nil
762}