~ubuntu-branches/ubuntu/trusty/enigmail/trusty-updates

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Chris Coulson
  • Date: 2011-06-07 14:35:53 UTC
  • mfrom: (0.12.1 upstream)
  • Revision ID: package-import@ubuntu.com-20110607143553-fbgqhhvh8g8h6j1y
Tags: 2:1.2~a2~cvs20110606t2200-0ubuntu1
* Update to latest trunk snapshot for Thunderbird beta compat

* Remove build/pgo/profileserver.py from debian/clean. The new build
  system has a target depending on this
  - update debian/clean
* Drop debian/patches/autoconf.diff, just generate this at build time
* Refresh debian/patches/build_system_dont_link_libxul.diff
* libipc seems to be renamed to libipc-pipe. Fix genxpi and chrome.manifest
  to fix this 
  - add debian/patches/ipc-pipe_rename.diff
  - update debian/patches/series
* The makefiles in extensions/enigmail/ipc have an incorrect DEPTH
  attribute. Fix this so that they can find the rest of the build system
  - add debian/patches/makefile_depth.diff
  - update debian/patches/series
* Drop debian/patches/makefile-in-empty-xpcom-fix.diff - fixed in the
  current version
* Don't register a class ID multiple times, as this breaks enigmail entirely
  - add debian/patches/dont_register_cids_multiple_times.diff
  - update debian/patches/series
* Look for the Thunderbird 5 SDK
  - update debian/rules
  - update debian/control
* Run autoconf2.13 at build time
  - update debian/rules
  - update debian/control
* Add useless mesa-common-dev build-dep, just to satisfy the build system.
  We should just patch this out entirely really, but that's for another upload
  - update debian/control

Show diffs side-by-side

added added

removed removed

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