~ubuntu-branches/ubuntu/quantal/enigmail/quantal-security

« back to all changes in this revision

Viewing changes to build/unix/elfhack/elf.cpp

  • Committer: Package Import Robot
  • Author(s): Chris Coulson
  • Date: 2013-09-13 16:02:15 UTC
  • mfrom: (0.12.16)
  • Revision ID: package-import@ubuntu.com-20130913160215-u3g8nmwa0pdwagwc
Tags: 2:1.5.2-0ubuntu0.12.10.1
* New upstream release v1.5.2 for Thunderbird 24

* Build enigmail using a stripped down Thunderbird 17 build system, as it's
  now quite difficult to build the way we were doing previously, with the
  latest Firefox build system
* Add debian/patches/no_libxpcom.patch - Don't link against libxpcom, as it
  doesn't exist anymore (but exists in the build system)
* Add debian/patches/use_sdk.patch - Use the SDK version of xpt.py and
  friends
* Drop debian/patches/ipc-pipe_rename.diff (not needed anymore)
* Drop debian/patches/makefile_depth.diff (not needed anymore)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
 
 
5
 
#undef NDEBUG
6
 
#include <cstring>
7
 
#include <assert.h>
8
 
#include "elfxx.h"
9
 
 
10
 
template <class endian, typename R, typename T>
11
 
void Elf_Ehdr_Traits::swap(T &t, R &r)
12
 
{
13
 
    memcpy(r.e_ident, t.e_ident, sizeof(r.e_ident));
14
 
    r.e_type = endian::swap(t.e_type);
15
 
    r.e_machine = endian::swap(t.e_machine);
16
 
    r.e_version = endian::swap(t.e_version);
17
 
    r.e_entry = endian::swap(t.e_entry);
18
 
    r.e_phoff = endian::swap(t.e_phoff);
19
 
    r.e_shoff = endian::swap(t.e_shoff);
20
 
    r.e_flags = endian::swap(t.e_flags);
21
 
    r.e_ehsize = endian::swap(t.e_ehsize);
22
 
    r.e_phentsize = endian::swap(t.e_phentsize);
23
 
    r.e_phnum = endian::swap(t.e_phnum);
24
 
    r.e_shentsize = endian::swap(t.e_shentsize);
25
 
    r.e_shnum = endian::swap(t.e_shnum);
26
 
    r.e_shstrndx = endian::swap(t.e_shstrndx);
27
 
}
28
 
 
29
 
template <class endian, typename R, typename T>
30
 
void Elf_Phdr_Traits::swap(T &t, R &r)
31
 
{
32
 
    r.p_type = endian::swap(t.p_type);
33
 
    r.p_offset = endian::swap(t.p_offset);
34
 
    r.p_vaddr = endian::swap(t.p_vaddr);
35
 
    r.p_paddr = endian::swap(t.p_paddr);
36
 
    r.p_filesz = endian::swap(t.p_filesz);
37
 
    r.p_memsz = endian::swap(t.p_memsz);
38
 
    r.p_flags = endian::swap(t.p_flags);
39
 
    r.p_align = endian::swap(t.p_align);
40
 
}
41
 
 
42
 
template <class endian, typename R, typename T>
43
 
void Elf_Shdr_Traits::swap(T &t, R &r)
44
 
{
45
 
    r.sh_name = endian::swap(t.sh_name);
46
 
    r.sh_type = endian::swap(t.sh_type);
47
 
    r.sh_flags = endian::swap(t.sh_flags);
48
 
    r.sh_addr = endian::swap(t.sh_addr);
49
 
    r.sh_offset = endian::swap(t.sh_offset);
50
 
    r.sh_size = endian::swap(t.sh_size);
51
 
    r.sh_link = endian::swap(t.sh_link);
52
 
    r.sh_info = endian::swap(t.sh_info);
53
 
    r.sh_addralign = endian::swap(t.sh_addralign);
54
 
    r.sh_entsize = endian::swap(t.sh_entsize);
55
 
}
56
 
 
57
 
template <class endian, typename R, typename T>
58
 
void Elf_Dyn_Traits::swap(T &t, R &r)
59
 
{
60
 
    r.d_tag = endian::swap(t.d_tag);
61
 
    r.d_un.d_val = endian::swap(t.d_un.d_val);
62
 
}
63
 
 
64
 
template <class endian, typename R, typename T>
65
 
void Elf_Sym_Traits::swap(T &t, R &r)
66
 
{
67
 
    r.st_name = endian::swap(t.st_name);
68
 
    r.st_value = endian::swap(t.st_value);
69
 
    r.st_size = endian::swap(t.st_size);
70
 
    r.st_info = t.st_info;
71
 
    r.st_other = t.st_other;
72
 
    r.st_shndx = endian::swap(t.st_shndx);
73
 
}
74
 
 
75
 
template <class endian>
76
 
struct _Rel_info {
77
 
    static inline void swap(Elf32_Word &t, Elf32_Word &r) { r = endian::swap(t); }
78
 
    static inline void swap(Elf64_Xword &t, Elf64_Xword &r) { r = endian::swap(t); }
79
 
    static inline void swap(Elf64_Xword &t, Elf32_Word &r) {
80
 
        r = endian::swap(ELF32_R_INFO(ELF64_R_SYM(t), ELF64_R_TYPE(t)));
81
 
    }
82
 
    static inline void swap(Elf32_Word &t, Elf64_Xword &r) {
83
 
        r = endian::swap(ELF64_R_INFO(ELF32_R_SYM(t), ELF32_R_TYPE(t)));
84
 
    }
85
 
};
86
 
 
87
 
template <class endian, typename R, typename T>
88
 
void Elf_Rel_Traits::swap(T &t, R &r)
89
 
{
90
 
    r.r_offset = endian::swap(t.r_offset);
91
 
    _Rel_info<endian>::swap(t.r_info, r.r_info);
92
 
}
93
 
 
94
 
template <class endian, typename R, typename T>
95
 
void Elf_Rela_Traits::swap(T &t, R &r)
96
 
{
97
 
    r.r_offset = endian::swap(t.r_offset);
98
 
    _Rel_info<endian>::swap(t.r_info, r.r_info);
99
 
    r.r_addend = endian::swap(t.r_addend);
100
 
}
101
 
 
102
 
static const Elf32_Shdr null32_section =
103
 
    { 0, SHT_NULL, 0, 0, 0, 0, SHN_UNDEF, 0, 0, 0 };
104
 
 
105
 
Elf_Shdr null_section(null32_section);
106
 
 
107
 
Elf_Ehdr::Elf_Ehdr(std::ifstream &file, char ei_class, char ei_data)
108
 
: serializable<Elf_Ehdr_Traits>(file, ei_class, ei_data),
109
 
  ElfSection(null_section, NULL, NULL)
110
 
{
111
 
    shdr.sh_size = Elf_Ehdr::size(ei_class);
112
 
}
113
 
 
114
 
Elf::Elf(std::ifstream &file)
115
 
{
116
 
    if (!file.is_open())
117
 
        throw std::runtime_error("Error opening file");
118
 
 
119
 
    file.exceptions(std::ifstream::eofbit | std::ifstream::failbit | std::ifstream::badbit);
120
 
    // Read ELF magic number and identification information
121
 
    char e_ident[EI_VERSION];
122
 
    file.seekg(0);
123
 
    file.read(e_ident, sizeof(e_ident));
124
 
    file.seekg(0);
125
 
    ehdr = new Elf_Ehdr(file, e_ident[EI_CLASS], e_ident[EI_DATA]);
126
 
 
127
 
    // ELFOSABI_LINUX is kept unsupported because I haven't looked whether
128
 
    // STB_GNU_UNIQUE or STT_GNU_IFUNC would need special casing.
129
 
    if ((ehdr->e_ident[EI_OSABI] != ELFOSABI_NONE) && (ehdr->e_ident[EI_ABIVERSION] != 0))
130
 
        throw std::runtime_error("unsupported ELF ABI");
131
 
 
132
 
    if (ehdr->e_version != 1)
133
 
        throw std::runtime_error("unsupported ELF version");
134
 
 
135
 
    // Sanity checks
136
 
    if (ehdr->e_shnum == 0)
137
 
        throw std::runtime_error("sstripped ELF files aren't supported");
138
 
 
139
 
    if (ehdr->e_ehsize != Elf_Ehdr::size(e_ident[EI_CLASS]))
140
 
        throw std::runtime_error("unsupported ELF inconsistency: ehdr.e_ehsize != sizeof(ehdr)");
141
 
 
142
 
    if (ehdr->e_shentsize != Elf_Shdr::size(e_ident[EI_CLASS]))
143
 
        throw std::runtime_error("unsupported ELF inconsistency: ehdr.e_shentsize != sizeof(shdr)");
144
 
 
145
 
    if (ehdr->e_phnum == 0) {
146
 
        if (ehdr->e_phoff != 0)
147
 
            throw std::runtime_error("unsupported ELF inconsistency: e_phnum == 0 && e_phoff != 0");
148
 
        if (ehdr->e_phentsize != 0)
149
 
            throw std::runtime_error("unsupported ELF inconsistency: e_phnum == 0 && e_phentsize != 0");
150
 
    } else if (ehdr->e_phoff != ehdr->e_ehsize)
151
 
        throw std::runtime_error("unsupported ELF inconsistency: ehdr->e_phoff != ehdr->e_ehsize");
152
 
    else if (ehdr->e_phentsize != Elf_Phdr::size(e_ident[EI_CLASS]))
153
 
        throw std::runtime_error("unsupported ELF inconsistency: ehdr->e_phentsize != sizeof(phdr)");
154
 
 
155
 
    // Read section headers
156
 
    Elf_Shdr **shdr = new Elf_Shdr *[ehdr->e_shnum];
157
 
    file.seekg(ehdr->e_shoff);
158
 
    for (int i = 0; i < ehdr->e_shnum; i++)
159
 
        shdr[i] = new Elf_Shdr(file, e_ident[EI_CLASS], e_ident[EI_DATA]);
160
 
 
161
 
    // Sanity check in section header for index 0
162
 
    if ((shdr[0]->sh_name != 0) || (shdr[0]->sh_type != SHT_NULL) ||
163
 
        (shdr[0]->sh_flags != 0) || (shdr[0]->sh_addr != 0) ||
164
 
        (shdr[0]->sh_offset != 0) || (shdr[0]->sh_size != 0) ||
165
 
        (shdr[0]->sh_link != SHN_UNDEF) || (shdr[0]->sh_info != 0) ||
166
 
        (shdr[0]->sh_addralign != 0) || (shdr[0]->sh_entsize != 0))
167
 
        throw std::runtime_error("Section header for index 0 contains unsupported values");
168
 
 
169
 
    if ((shdr[ehdr->e_shstrndx]->sh_link != 0) || (shdr[ehdr->e_shstrndx]->sh_info != 0))
170
 
        throw std::runtime_error("unsupported ELF content: string table with sh_link != 0 || sh_info != 0");
171
 
 
172
 
    // Store these temporarily
173
 
    tmp_shdr = shdr;
174
 
    tmp_file = &file;
175
 
 
176
 
    // Fill sections list
177
 
    sections = new ElfSection *[ehdr->e_shnum];
178
 
    for (int i = 0; i < ehdr->e_shnum; i++)
179
 
        sections[i] = NULL;
180
 
    for (int i = 1; i < ehdr->e_shnum; i++) {
181
 
        if (sections[i] != NULL)
182
 
            continue;
183
 
        getSection(i);
184
 
    }
185
 
    Elf_Shdr s;
186
 
    s.sh_name = 0;
187
 
    s.sh_type = SHT_NULL;
188
 
    s.sh_flags = 0;
189
 
    s.sh_addr = 0;
190
 
    s.sh_offset = ehdr->e_shoff;
191
 
    s.sh_entsize = Elf_Shdr::size(e_ident[EI_CLASS]);
192
 
    s.sh_size = s.sh_entsize * ehdr->e_shnum;
193
 
    s.sh_link = 0;
194
 
    s.sh_info = 0;
195
 
    s.sh_addralign = (e_ident[EI_CLASS] == ELFCLASS32) ? 4 : 8;
196
 
    shdr_section = new ElfSection(s, NULL, NULL);
197
 
 
198
 
    // Fake section for program headers
199
 
    s.sh_offset = ehdr->e_phoff;
200
 
    s.sh_addr = ehdr->e_phoff;
201
 
    s.sh_entsize = Elf_Phdr::size(e_ident[EI_CLASS]);
202
 
    s.sh_size = s.sh_entsize * ehdr->e_phnum;
203
 
    phdr_section = new ElfSection(s, NULL, NULL);
204
 
 
205
 
    phdr_section->insertAfter(ehdr, false);
206
 
 
207
 
    sections[1]->insertAfter(phdr_section, false);
208
 
    for (int i = 2; i < ehdr->e_shnum; i++) {
209
 
        // TODO: this should be done in a better way
210
 
        if ((shdr_section->getPrevious() == NULL) && (shdr[i]->sh_offset > ehdr->e_shoff)) {
211
 
            shdr_section->insertAfter(sections[i - 1], false);
212
 
            sections[i]->insertAfter(shdr_section, false);
213
 
        } else
214
 
            sections[i]->insertAfter(sections[i - 1], false);
215
 
    }
216
 
    if (shdr_section->getPrevious() == NULL)
217
 
        shdr_section->insertAfter(sections[ehdr->e_shnum - 1], false);
218
 
 
219
 
    tmp_file = NULL;
220
 
    tmp_shdr = NULL;
221
 
    for (int i = 0; i < ehdr->e_shnum; i++)
222
 
        delete shdr[i];
223
 
    delete[] shdr;
224
 
 
225
 
    eh_shstrndx = (ElfStrtab_Section *)sections[ehdr->e_shstrndx];
226
 
 
227
 
    // Skip reading program headers if there aren't any
228
 
    if (ehdr->e_phnum == 0)
229
 
        return;
230
 
 
231
 
    // Read program headers
232
 
    file.seekg(ehdr->e_phoff);
233
 
    for (int i = 0; i < ehdr->e_phnum; i++) {
234
 
        Elf_Phdr phdr(file, e_ident[EI_CLASS], e_ident[EI_DATA]);
235
 
        if (phdr.p_type == PT_LOAD) {
236
 
            // Default alignment for PT_LOAD on x86-64 prevents elfhack from
237
 
            // doing anything useful. However, the system doesn't actually
238
 
            // require such a big alignment, so in order for elfhack to work
239
 
            // efficiently, reduce alignment when it's originally the default
240
 
            // one.
241
 
            if ((ehdr->e_machine == EM_X86_64) && (phdr.p_align == 0x200000))
242
 
              phdr.p_align = 0x1000;
243
 
        }
244
 
        ElfSegment *segment = new ElfSegment(&phdr);
245
 
        // Some segments aren't entirely filled (if at all) by sections
246
 
        // For those, we use fake sections
247
 
        if ((phdr.p_type == PT_LOAD) && (phdr.p_offset == 0)) {
248
 
            // Use a fake section for ehdr and phdr
249
 
            ehdr->getShdr().sh_addr = phdr.p_vaddr;
250
 
            phdr_section->getShdr().sh_addr += phdr.p_vaddr;
251
 
            segment->addSection(ehdr);
252
 
            segment->addSection(phdr_section);
253
 
        }
254
 
        if (phdr.p_type == PT_PHDR)
255
 
            segment->addSection(phdr_section);
256
 
        for (int j = 1; j < ehdr->e_shnum; j++)
257
 
            if (phdr.contains(sections[j]))
258
 
                segment->addSection(sections[j]);
259
 
        // Make sure that our view of segments corresponds to the original
260
 
        // ELF file.
261
 
        assert(segment->getFileSize() == phdr.p_filesz);
262
 
        assert(segment->getMemSize() == phdr.p_memsz);
263
 
        segments.push_back(segment);
264
 
    }
265
 
 
266
 
    new (&eh_entry) ElfLocation(ehdr->e_entry, this);
267
 
}
268
 
 
269
 
Elf::~Elf()
270
 
{
271
 
    for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++)
272
 
        delete *seg;
273
 
    delete[] sections;
274
 
    ElfSection *section = ehdr;
275
 
    while (section != NULL) {
276
 
        ElfSection *next = section->getNext();
277
 
        delete section;
278
 
        section = next;
279
 
    }
280
 
}
281
 
 
282
 
// TODO: This shouldn't fail after inserting sections
283
 
ElfSection *Elf::getSection(int index)
284
 
{
285
 
    if ((index < -1) || (index >= ehdr->e_shnum))
286
 
        throw std::runtime_error("Section index out of bounds");
287
 
    if (index == -1)
288
 
        index = ehdr->e_shstrndx; // TODO: should be fixed to use the actual current number
289
 
    // Special case: the section at index 0 is void
290
 
    if (index == 0)
291
 
        return NULL;
292
 
    // Infinite recursion guard
293
 
    if (sections[index] == (ElfSection *)this)
294
 
        return NULL;
295
 
    if (sections[index] == NULL) {
296
 
        sections[index] = (ElfSection *)this;
297
 
        switch (tmp_shdr[index]->sh_type) {
298
 
        case SHT_DYNAMIC:
299
 
            sections[index] = new ElfDynamic_Section(*tmp_shdr[index], tmp_file, this);
300
 
            break;
301
 
        case SHT_REL:
302
 
            sections[index] = new ElfRel_Section<Elf_Rel>(*tmp_shdr[index], tmp_file, this);
303
 
            break;
304
 
        case SHT_RELA:
305
 
            sections[index] = new ElfRel_Section<Elf_Rela>(*tmp_shdr[index], tmp_file, this);
306
 
            break;
307
 
        case SHT_DYNSYM:
308
 
        case SHT_SYMTAB:
309
 
            sections[index] = new ElfSymtab_Section(*tmp_shdr[index], tmp_file, this);
310
 
            break;
311
 
        case SHT_STRTAB:
312
 
            sections[index] = new ElfStrtab_Section(*tmp_shdr[index], tmp_file, this);
313
 
            break;
314
 
        default:
315
 
            sections[index] = new ElfSection(*tmp_shdr[index], tmp_file, this);
316
 
        }
317
 
    }
318
 
    return sections[index];
319
 
}
320
 
 
321
 
ElfSection *Elf::getSectionAt(unsigned int offset)
322
 
{
323
 
    for (int i = 1; i < ehdr->e_shnum; i++) {
324
 
        ElfSection *section = getSection(i);
325
 
        if ((section != NULL) && (section->getFlags() & SHF_ALLOC) && !(section->getFlags() & SHF_TLS) &&
326
 
            (offset >= section->getAddr()) && (offset < section->getAddr() + section->getSize()))
327
 
            return section;
328
 
    }
329
 
    return NULL;
330
 
}
331
 
 
332
 
ElfSegment *Elf::getSegmentByType(unsigned int type)
333
 
{
334
 
    for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++)
335
 
        if ((*seg)->getType() == type)
336
 
            return *seg;
337
 
    return NULL;
338
 
}
339
 
 
340
 
ElfDynamic_Section *Elf::getDynSection()
341
 
{
342
 
    for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++)
343
 
        if (((*seg)->getType() == PT_DYNAMIC) && ((*seg)->getFirstSection() != NULL) &&
344
 
            (*seg)->getFirstSection()->getType() == SHT_DYNAMIC)
345
 
            return (ElfDynamic_Section *)(*seg)->getFirstSection();
346
 
 
347
 
    return NULL;
348
 
}
349
 
 
350
 
void Elf::normalize()
351
 
{
352
 
    // fixup section headers sh_name; TODO: that should be done by sections
353
 
    // themselves
354
 
    for (ElfSection *section = ehdr; section != NULL; section = section->getNext()) {
355
 
        if (section->getIndex() == 0)
356
 
            continue;
357
 
        else
358
 
            ehdr->e_shnum = section->getIndex() + 1;
359
 
        section->getShdr().sh_name = eh_shstrndx->getStrIndex(section->getName());
360
 
    }
361
 
    ehdr->markDirty();
362
 
    // Adjust PT_LOAD segments
363
 
    int i = 0;
364
 
    for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++, i++) {
365
 
        if ((*seg)->getType() == PT_LOAD) {
366
 
            std::list<ElfSection *>::iterator it = (*seg)->begin();
367
 
            for (ElfSection *last = *(it++); it != (*seg)->end(); last = *(it++)) {
368
 
               if (((*it)->getType() != SHT_NOBITS) &&
369
 
                   ((*it)->getAddr() - last->getAddr()) != ((*it)->getOffset() - last->getOffset())) {
370
 
                   std::vector<ElfSegment *>::iterator next = seg;
371
 
                   segments.insert(++next, (*seg)->splitBefore(*it));
372
 
                   seg = segments.begin() + i;
373
 
                   break;
374
 
               }
375
 
           }
376
 
        }
377
 
    }
378
 
    // fixup ehdr before writing
379
 
    if (ehdr->e_phnum != segments.size()) {
380
 
        ehdr->e_phnum = segments.size();
381
 
        phdr_section->getShdr().sh_size = segments.size() * Elf_Phdr::size(ehdr->e_ident[EI_CLASS]);
382
 
        phdr_section->getNext()->markDirty();
383
 
    }
384
 
    // fixup shdr before writing
385
 
    if (ehdr->e_shnum != shdr_section->getSize() / shdr_section->getEntSize())
386
 
        shdr_section->getShdr().sh_size = ehdr->e_shnum * Elf_Shdr::size(ehdr->e_ident[EI_CLASS]);
387
 
    ehdr->e_shoff = shdr_section->getOffset();
388
 
    ehdr->e_entry = eh_entry.getValue();
389
 
    ehdr->e_shstrndx = eh_shstrndx->getIndex();
390
 
}
391
 
 
392
 
void Elf::write(std::ofstream &file)
393
 
{
394
 
    normalize();
395
 
    for (ElfSection *section = ehdr;
396
 
         section != NULL; section = section->getNext()) {
397
 
        file.seekp(section->getOffset());
398
 
        if (section == phdr_section) {
399
 
            for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++) {
400
 
                Elf_Phdr phdr;
401
 
                phdr.p_type = (*seg)->getType();
402
 
                phdr.p_flags = (*seg)->getFlags();
403
 
                phdr.p_offset = (*seg)->getOffset();
404
 
                phdr.p_vaddr = (*seg)->getAddr();
405
 
                phdr.p_paddr = phdr.p_vaddr + (*seg)->getVPDiff();
406
 
                phdr.p_filesz = (*seg)->getFileSize();
407
 
                phdr.p_memsz = (*seg)->getMemSize();
408
 
                phdr.p_align = (*seg)->getAlign();
409
 
                phdr.serialize(file, ehdr->e_ident[EI_CLASS], ehdr->e_ident[EI_DATA]);
410
 
            }
411
 
        } else if (section == shdr_section) {
412
 
            null_section.serialize(file, ehdr->e_ident[EI_CLASS], ehdr->e_ident[EI_DATA]);
413
 
            for (ElfSection *sec = ehdr; sec!= NULL; sec = sec->getNext()) {
414
 
                if (sec->getType() != SHT_NULL)
415
 
                    sec->getShdr().serialize(file, ehdr->e_ident[EI_CLASS], ehdr->e_ident[EI_DATA]);
416
 
            }
417
 
        } else
418
 
           section->serialize(file, ehdr->e_ident[EI_CLASS], ehdr->e_ident[EI_DATA]);
419
 
    }
420
 
}
421
 
 
422
 
ElfSection::ElfSection(Elf_Shdr &s, std::ifstream *file, Elf *parent)
423
 
: shdr(s),
424
 
  link(shdr.sh_link == SHN_UNDEF ? NULL : parent->getSection(shdr.sh_link)),
425
 
  next(NULL), previous(NULL), index(-1)
426
 
{
427
 
    if ((file == NULL) || (shdr.sh_type == SHT_NULL) || (shdr.sh_type == SHT_NOBITS))
428
 
        data = NULL;
429
 
    else {
430
 
        data = new char[shdr.sh_size];
431
 
        int pos = file->tellg();
432
 
        file->seekg(shdr.sh_offset);
433
 
        file->read(data, shdr.sh_size);
434
 
        file->seekg(pos);
435
 
    }
436
 
    if (shdr.sh_name == 0)
437
 
        name = NULL;
438
 
    else {
439
 
        ElfStrtab_Section *strtab = (ElfStrtab_Section *) parent->getSection(-1);
440
 
        // Special case (see elfgeneric.cpp): if strtab is NULL, the
441
 
        // section being created is the strtab.
442
 
        if (strtab == NULL)
443
 
            name = &data[shdr.sh_name];
444
 
        else
445
 
            name = strtab->getStr(shdr.sh_name);
446
 
    }
447
 
    // Only SHT_REL/SHT_RELA sections use sh_info to store a section
448
 
    // number.
449
 
    if ((shdr.sh_type == SHT_REL) || (shdr.sh_type == SHT_RELA))
450
 
        info.section = shdr.sh_info ? parent->getSection(shdr.sh_info) : NULL;
451
 
    else
452
 
        info.index = shdr.sh_info;
453
 
}
454
 
 
455
 
unsigned int ElfSection::getAddr()
456
 
{
457
 
    if (shdr.sh_addr != (Elf32_Word)-1)
458
 
        return shdr.sh_addr;
459
 
 
460
 
    // It should be safe to adjust sh_addr for all allocated sections that
461
 
    // are neither SHT_NOBITS nor SHT_PROGBITS
462
 
    if ((previous != NULL) && isRelocatable()) {
463
 
        unsigned int addr = previous->getAddr();
464
 
        if (previous->getType() != SHT_NOBITS)
465
 
            addr += previous->getSize();
466
 
 
467
 
        if (addr & (getAddrAlign() - 1))
468
 
            addr = (addr | (getAddrAlign() - 1)) + 1;
469
 
 
470
 
        return (shdr.sh_addr = addr);
471
 
    }
472
 
    return shdr.sh_addr;
473
 
}
474
 
 
475
 
unsigned int ElfSection::getOffset()
476
 
{
477
 
    if (shdr.sh_offset != (Elf32_Word)-1)
478
 
        return shdr.sh_offset;
479
 
 
480
 
    if (previous == NULL)
481
 
        return (shdr.sh_offset = 0);
482
 
 
483
 
    unsigned int offset = previous->getOffset();
484
 
    if (previous->getType() != SHT_NOBITS)
485
 
        offset += previous->getSize();
486
 
 
487
 
    Elf32_Word align = 0x1000;
488
 
    for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++)
489
 
        align = std::max(align, (*seg)->getAlign());
490
 
 
491
 
    Elf32_Word mask = align - 1;
492
 
    // SHF_TLS is used for .tbss which is some kind of special case.
493
 
    if (((getType() != SHT_NOBITS) || (getFlags() & SHF_TLS)) && (getFlags() & SHF_ALLOC)) {
494
 
        if ((getAddr() & mask) < (offset & mask))
495
 
            offset = (offset | mask) + (getAddr() & mask) + 1;
496
 
        else
497
 
            offset = (offset & ~mask) + (getAddr() & mask);
498
 
    }
499
 
    if ((getType() != SHT_NOBITS) && (offset & (getAddrAlign() - 1)))
500
 
        offset = (offset | (getAddrAlign() - 1)) + 1;
501
 
 
502
 
    // Two subsequent sections can't be mapped in the same page in memory
503
 
    // if they aren't in the same 4K block on disk.
504
 
    if ((getType() != SHT_NOBITS) && getAddr()) {
505
 
        if (((offset >> 12) != (previous->getOffset() >> 12)) &&
506
 
            ((getAddr() >> 12) == (previous->getAddr() >> 12)))
507
 
            throw std::runtime_error("Moving section would require overlapping segments");
508
 
    }
509
 
 
510
 
    return (shdr.sh_offset = offset);
511
 
}
512
 
 
513
 
int ElfSection::getIndex()
514
 
{
515
 
    if (index != -1)
516
 
        return index;
517
 
    if (getType() == SHT_NULL)
518
 
        return (index = 0);
519
 
    ElfSection *reference;
520
 
    for (reference = previous; (reference != NULL) && (reference->getType() == SHT_NULL); reference = reference->getPrevious());
521
 
    if (reference == NULL)
522
 
        return (index = 1);
523
 
    return (index = reference->getIndex() + 1);
524
 
}
525
 
 
526
 
Elf_Shdr &ElfSection::getShdr()
527
 
{
528
 
    getOffset();
529
 
    if (shdr.sh_link == (Elf32_Word)-1)
530
 
        shdr.sh_link = getLink() ? getLink()->getIndex() : 0;
531
 
    if (shdr.sh_info == (Elf32_Word)-1)
532
 
        shdr.sh_info = ((getType() == SHT_REL) || (getType() == SHT_RELA)) ?
533
 
                       (getInfo().section ? getInfo().section->getIndex() : 0) :
534
 
                       getInfo().index;
535
 
 
536
 
    return shdr;
537
 
}
538
 
 
539
 
ElfSegment::ElfSegment(Elf_Phdr *phdr)
540
 
: type(phdr->p_type), v_p_diff(phdr->p_paddr - phdr->p_vaddr),
541
 
  flags(phdr->p_flags), align(phdr->p_align), vaddr(phdr->p_vaddr),
542
 
  filesz(phdr->p_filesz), memsz(phdr->p_memsz) {}
543
 
 
544
 
void ElfSegment::addSection(ElfSection *section)
545
 
{
546
 
    // Make sure all sections in PT_GNU_RELRO won't be moved by elfhack
547
 
    assert(!((type == PT_GNU_RELRO) && (section->isRelocatable())));
548
 
 
549
 
    //TODO: Check overlapping sections
550
 
    std::list<ElfSection *>::iterator i;
551
 
    for (i = sections.begin(); i != sections.end(); ++i)
552
 
        if ((*i)->getAddr() > section->getAddr())
553
 
            break;
554
 
    sections.insert(i, section);
555
 
    section->addToSegment(this);
556
 
}
557
 
 
558
 
unsigned int ElfSegment::getFileSize()
559
 
{
560
 
    if (type == PT_GNU_RELRO)
561
 
        return filesz;
562
 
 
563
 
    if (sections.empty())
564
 
        return 0;
565
 
    // Search the last section that is not SHT_NOBITS
566
 
    std::list<ElfSection *>::reverse_iterator i;
567
 
    for (i = sections.rbegin(); (i != sections.rend()) && ((*i)->getType() == SHT_NOBITS); ++i);
568
 
    // All sections are SHT_NOBITS
569
 
    if (i == sections.rend())
570
 
        return 0;
571
 
 
572
 
    unsigned int end = (*i)->getAddr() + (*i)->getSize();
573
 
 
574
 
    return end - sections.front()->getAddr();
575
 
}
576
 
 
577
 
unsigned int ElfSegment::getMemSize()
578
 
{
579
 
    if (type == PT_GNU_RELRO)
580
 
        return memsz;
581
 
 
582
 
    if (sections.empty())
583
 
        return 0;
584
 
 
585
 
    unsigned int end = sections.back()->getAddr() + sections.back()->getSize();
586
 
 
587
 
    return end - sections.front()->getAddr();
588
 
}
589
 
 
590
 
unsigned int ElfSegment::getOffset()
591
 
{
592
 
    if ((type == PT_GNU_RELRO) && !sections.empty() &&
593
 
        (sections.front()->getAddr() != vaddr))
594
 
        throw std::runtime_error("PT_GNU_RELRO segment doesn't start on a section start");
595
 
 
596
 
    return sections.empty() ? 0 : sections.front()->getOffset();
597
 
}
598
 
 
599
 
unsigned int ElfSegment::getAddr()
600
 
{
601
 
    if ((type == PT_GNU_RELRO) && !sections.empty() &&
602
 
        (sections.front()->getAddr() != vaddr))
603
 
        throw std::runtime_error("PT_GNU_RELRO segment doesn't start on a section start");
604
 
 
605
 
    return sections.empty() ? 0 : sections.front()->getAddr();
606
 
}
607
 
 
608
 
ElfSegment *ElfSegment::splitBefore(ElfSection *section)
609
 
{
610
 
    std::list<ElfSection *>::iterator i, rm;
611
 
    for (i = sections.begin(); (*i != section) && (i != sections.end()); ++i);
612
 
    if (i == sections.end())
613
 
        return NULL;
614
 
 
615
 
    // Probably very wrong.
616
 
    Elf_Phdr phdr;
617
 
    phdr.p_type = type;
618
 
    phdr.p_vaddr = 0;
619
 
    phdr.p_paddr = phdr.p_vaddr + v_p_diff;
620
 
    phdr.p_flags = flags;
621
 
    phdr.p_align = getAlign();
622
 
    phdr.p_filesz = (unsigned int)-1;
623
 
    phdr.p_memsz = (unsigned int)-1;
624
 
    ElfSegment *segment = new ElfSegment(&phdr);
625
 
 
626
 
    for (rm = i; i != sections.end(); ++i) {
627
 
        (*i)->removeFromSegment(this);
628
 
        segment->addSection(*i);
629
 
    }
630
 
    sections.erase(rm, sections.end());
631
 
 
632
 
    return segment;
633
 
}
634
 
 
635
 
ElfValue *ElfDynamic_Section::getValueForType(unsigned int tag)
636
 
{
637
 
    for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++)
638
 
        if (dyns[i].tag == tag)
639
 
            return dyns[i].value;
640
 
 
641
 
    return NULL;
642
 
}
643
 
 
644
 
ElfSection *ElfDynamic_Section::getSectionForType(unsigned int tag)
645
 
{
646
 
    ElfValue *value = getValueForType(tag);
647
 
    return value ? value->getSection() : NULL;
648
 
}
649
 
 
650
 
bool ElfDynamic_Section::setValueForType(unsigned int tag, ElfValue *val)
651
 
{
652
 
    unsigned int i;
653
 
    unsigned int shnum = shdr.sh_size / shdr.sh_entsize;
654
 
    for (i = 0; (i < shnum) && (dyns[i].tag != DT_NULL); i++)
655
 
        if (dyns[i].tag == tag) {
656
 
            delete dyns[i].value;
657
 
            dyns[i].value = val;
658
 
            return true;
659
 
        }
660
 
    // If we get here, this means we didn't match for the given tag
661
 
    // Most of the time, there are a few DT_NULL entries, that we can
662
 
    // use to add our value, but if we are on the last entry, we can't.
663
 
    if (i >= shnum - 1)
664
 
        return false;
665
 
 
666
 
    dyns[i].tag = tag;
667
 
    dyns[i].value = val;
668
 
    return true;
669
 
}
670
 
 
671
 
ElfDynamic_Section::ElfDynamic_Section(Elf_Shdr &s, std::ifstream *file, Elf *parent)
672
 
: ElfSection(s, file, parent)
673
 
{
674
 
    int pos = file->tellg();
675
 
    dyns.resize(s.sh_size / s.sh_entsize);
676
 
    file->seekg(shdr.sh_offset);
677
 
    // Here we assume tags refer to only one section (e.g. DT_RELSZ accounts
678
 
    // for .rel.dyn size)
679
 
    for (unsigned int i = 0; i < s.sh_size / s.sh_entsize; i++) {
680
 
        Elf_Dyn dyn(*file, parent->getClass(), parent->getData());
681
 
        dyns[i].tag = dyn.d_tag;
682
 
        switch (dyn.d_tag) {
683
 
        case DT_NULL:
684
 
        case DT_SYMBOLIC:
685
 
        case DT_TEXTREL:
686
 
        case DT_BIND_NOW:
687
 
            dyns[i].value = new ElfValue();
688
 
            break;
689
 
        case DT_NEEDED:
690
 
        case DT_SONAME:
691
 
        case DT_RPATH:
692
 
        case DT_PLTREL:
693
 
        case DT_RUNPATH:
694
 
        case DT_FLAGS:
695
 
        case DT_RELACOUNT:
696
 
        case DT_RELCOUNT:
697
 
        case DT_VERDEFNUM:
698
 
        case DT_VERNEEDNUM:
699
 
            dyns[i].value = new ElfPlainValue(dyn.d_un.d_val);
700
 
            break;
701
 
        case DT_PLTGOT:
702
 
        case DT_HASH:
703
 
        case DT_STRTAB:
704
 
        case DT_SYMTAB:
705
 
        case DT_RELA:
706
 
        case DT_INIT:
707
 
        case DT_FINI:
708
 
        case DT_REL:
709
 
        case DT_JMPREL:
710
 
        case DT_INIT_ARRAY:
711
 
        case DT_FINI_ARRAY:
712
 
        case DT_GNU_HASH:
713
 
        case DT_VERSYM:
714
 
        case DT_VERNEED:
715
 
        case DT_VERDEF:
716
 
            dyns[i].value = new ElfLocation(dyn.d_un.d_ptr, parent);
717
 
            break;
718
 
        default:
719
 
            dyns[i].value = NULL;
720
 
        }
721
 
    }
722
 
    // Another loop to get the section sizes
723
 
    for (unsigned int i = 0; i < s.sh_size / s.sh_entsize; i++)
724
 
        switch (dyns[i].tag) {
725
 
        case DT_PLTRELSZ:
726
 
            dyns[i].value = new ElfSize(getSectionForType(DT_JMPREL));
727
 
            break;
728
 
        case DT_RELASZ:
729
 
            dyns[i].value = new ElfSize(getSectionForType(DT_RELA));
730
 
            break;
731
 
        case DT_STRSZ:
732
 
            dyns[i].value = new ElfSize(getSectionForType(DT_STRTAB));
733
 
            break;
734
 
        case DT_RELSZ:
735
 
            dyns[i].value = new ElfSize(getSectionForType(DT_REL));
736
 
            break;
737
 
        case DT_INIT_ARRAYSZ:
738
 
            dyns[i].value = new ElfSize(getSectionForType(DT_INIT_ARRAY));
739
 
            break;
740
 
        case DT_FINI_ARRAYSZ:
741
 
            dyns[i].value = new ElfSize(getSectionForType(DT_FINI_ARRAY));
742
 
            break;
743
 
        case DT_RELAENT:
744
 
            dyns[i].value = new ElfEntSize(getSectionForType(DT_RELA));
745
 
            break;
746
 
        case DT_SYMENT:
747
 
            dyns[i].value = new ElfEntSize(getSectionForType(DT_SYMTAB));
748
 
            break;
749
 
        case DT_RELENT:
750
 
            dyns[i].value = new ElfEntSize(getSectionForType(DT_REL));
751
 
            break;
752
 
        }
753
 
 
754
 
    file->seekg(pos);
755
 
}
756
 
 
757
 
ElfDynamic_Section::~ElfDynamic_Section()
758
 
{
759
 
    for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++)
760
 
        delete dyns[i].value;
761
 
}
762
 
 
763
 
void ElfDynamic_Section::serialize(std::ofstream &file, char ei_class, char ei_data)
764
 
{
765
 
    for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) {
766
 
        Elf_Dyn dyn;
767
 
        dyn.d_tag = dyns[i].tag;
768
 
        dyn.d_un.d_val = (dyns[i].value != NULL) ? dyns[i].value->getValue() : 0;
769
 
        dyn.serialize(file, ei_class, ei_data);
770
 
    }
771
 
}
772
 
 
773
 
ElfSymtab_Section::ElfSymtab_Section(Elf_Shdr &s, std::ifstream *file, Elf *parent)
774
 
: ElfSection(s, file, parent)
775
 
{
776
 
    int pos = file->tellg();
777
 
    syms.resize(s.sh_size / s.sh_entsize);
778
 
    ElfStrtab_Section *strtab = (ElfStrtab_Section *)getLink();
779
 
    file->seekg(shdr.sh_offset);
780
 
    for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) {
781
 
        Elf_Sym sym(*file, parent->getClass(), parent->getData());
782
 
        syms[i].name = strtab->getStr(sym.st_name);
783
 
        syms[i].info = sym.st_info;
784
 
        syms[i].other = sym.st_other;
785
 
        ElfSection *section = (sym.st_shndx == SHN_ABS) ? NULL : parent->getSection(sym.st_shndx);
786
 
        new (&syms[i].value) ElfLocation(section, sym.st_value, ElfLocation::ABSOLUTE);
787
 
        syms[i].size = sym.st_size;
788
 
        syms[i].defined = (sym.st_shndx != SHN_UNDEF);
789
 
    }
790
 
    file->seekg(pos);
791
 
}
792
 
 
793
 
void
794
 
ElfSymtab_Section::serialize(std::ofstream &file, char ei_class, char ei_data)
795
 
{
796
 
    ElfStrtab_Section *strtab = (ElfStrtab_Section *)getLink();
797
 
    for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) {
798
 
        Elf_Sym sym;
799
 
        sym.st_name = strtab->getStrIndex(syms[i].name);
800
 
        sym.st_info = syms[i].info;
801
 
        sym.st_other = syms[i].other;
802
 
        sym.st_value = syms[i].value.getValue();
803
 
        ElfSection *section = syms[i].value.getSection();
804
 
        if (syms[i].defined)
805
 
            sym.st_shndx = section ? section->getIndex() : SHN_ABS;
806
 
        else
807
 
            sym.st_shndx = SHN_UNDEF;
808
 
        sym.st_size = syms[i].size;
809
 
        sym.serialize(file, ei_class, ei_data);
810
 
    }
811
 
}
812
 
 
813
 
Elf_SymValue *
814
 
ElfSymtab_Section::lookup(const char *name, unsigned int type_filter)
815
 
{
816
 
    for (std::vector<Elf_SymValue>::iterator sym = syms.begin();
817
 
         sym != syms.end(); sym++) {
818
 
        if ((type_filter & (1 << ELF32_ST_TYPE(sym->info))) &&
819
 
            (strcmp(sym->name, name) == 0)) {
820
 
            return &*sym;
821
 
        }
822
 
    }
823
 
    return NULL;
824
 
}
825
 
 
826
 
const char *
827
 
ElfStrtab_Section::getStr(unsigned int index)
828
 
{
829
 
    for (std::vector<table_storage>::iterator t = table.begin();
830
 
         t != table.end(); t++) {
831
 
        if (index < t->used)
832
 
            return t->buf + index;
833
 
        index -= t->used;
834
 
    }
835
 
    assert(1 == 0);
836
 
    return NULL;
837
 
}
838
 
 
839
 
const char *
840
 
ElfStrtab_Section::getStr(const char *string)
841
 
{
842
 
    if (string == NULL)
843
 
        return NULL;
844
 
 
845
 
    // If the given string is within the section, return it
846
 
    for (std::vector<table_storage>::iterator t = table.begin();
847
 
         t != table.end(); t++)
848
 
        if ((string >= t->buf) && (string < t->buf + t->used))
849
 
            return string;
850
 
 
851
 
    // TODO: should scan in the section to find an existing string
852
 
 
853
 
    // If not, we need to allocate the string in the section
854
 
    size_t len = strlen(string) + 1;
855
 
 
856
 
    if (table.back().size - table.back().used < len)
857
 
        table.resize(table.size() + 1);
858
 
 
859
 
    char *alloc_str = table.back().buf + table.back().used;
860
 
    memcpy(alloc_str, string, len);
861
 
    table.back().used += len;
862
 
 
863
 
    shdr.sh_size += len;
864
 
    markDirty();
865
 
 
866
 
    return alloc_str;
867
 
}
868
 
 
869
 
unsigned int
870
 
ElfStrtab_Section::getStrIndex(const char *string)
871
 
{
872
 
    if (string == NULL)
873
 
        return 0;
874
 
 
875
 
    unsigned int index = 0;
876
 
    string = getStr(string);
877
 
    for (std::vector<table_storage>::iterator t = table.begin();
878
 
         t != table.end(); t++) {
879
 
        if ((string >= t->buf) && (string < t->buf + t->used))
880
 
            return index + (string - t->buf);
881
 
        index += t->used;
882
 
    }
883
 
 
884
 
    assert(1 == 0);
885
 
    return 0;
886
 
}
887
 
 
888
 
void
889
 
ElfStrtab_Section::serialize(std::ofstream &file, char ei_class, char ei_data)
890
 
{
891
 
    file.seekp(getOffset());
892
 
    for (std::vector<table_storage>::iterator t = table.begin();
893
 
         t != table.end(); t++)
894
 
        file.write(t->buf, t->used);
895
 
}