build/unix/elfhack/elf.cpp

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rw-r--r--

Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

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

mercurial