1 #include "common/linux/synth_elf.h"
2 
3 #include <assert.h>
4 #include <elf.h>
5 #include <stdio.h>
6 #include <string.h>
7 
8 #include "common/linux/elf_gnu_compat.h"
9 #include "common/using_std_string.h"
10 
11 namespace google_breakpad {
12 namespace synth_elf {
13 
ELF(uint16_t machine,uint8_t file_class,Endianness endianness)14 ELF::ELF(uint16_t machine,
15          uint8_t file_class,
16          Endianness endianness)
17   : Section(endianness),
18     addr_size_(file_class == ELFCLASS64 ? 8 : 4),
19     program_count_(0),
20     program_header_table_(endianness),
21     section_count_(0),
22     section_header_table_(endianness),
23     section_header_strings_(endianness) {
24   // Could add support for more machine types here if needed.
25   assert(machine == EM_386 ||
26          machine == EM_X86_64 ||
27          machine == EM_ARM);
28   assert(file_class == ELFCLASS32 || file_class == ELFCLASS64);
29 
30   start() = 0;
31   // Add ELF header
32   // e_ident
33   // EI_MAG0...EI_MAG3
34   D8(ELFMAG0);
35   D8(ELFMAG1);
36   D8(ELFMAG2);
37   D8(ELFMAG3);
38   // EI_CLASS
39   D8(file_class);
40   // EI_DATA
41   D8(endianness == kLittleEndian ? ELFDATA2LSB : ELFDATA2MSB);
42   // EI_VERSION
43   D8(EV_CURRENT);
44   // EI_OSABI
45   D8(ELFOSABI_SYSV);
46   // EI_ABIVERSION
47   D8(0);
48   // EI_PAD
49   Append(7, 0);
50   assert(Size() == EI_NIDENT);
51 
52   // e_type
53   D16(ET_EXEC);  //TODO: allow passing ET_DYN?
54   // e_machine
55   D16(machine);
56   // e_version
57   D32(EV_CURRENT);
58   // e_entry
59   Append(endianness, addr_size_, 0);
60   // e_phoff
61   Append(endianness, addr_size_, program_header_label_);
62   // e_shoff
63   Append(endianness, addr_size_, section_header_label_);
64   // e_flags
65   D32(0);
66   // e_ehsize
67   D16(addr_size_ == 8 ? sizeof(Elf64_Ehdr) : sizeof(Elf32_Ehdr));
68   // e_phentsize
69   D16(addr_size_ == 8 ? sizeof(Elf64_Phdr) : sizeof(Elf32_Phdr));
70   // e_phnum
71   D16(program_count_label_);
72   // e_shentsize
73   D16(addr_size_ == 8 ? sizeof(Elf64_Shdr) : sizeof(Elf32_Shdr));
74   // e_shnum
75   D16(section_count_label_);
76   // e_shstrndx
77   D16(section_header_string_index_);
78 
79   // Add an empty section for SHN_UNDEF.
80   Section shn_undef;
81   AddSection("", shn_undef, SHT_NULL);
82 }
83 
AddSection(const string & name,const Section & section,uint32_t type,uint32_t flags,uint64_t addr,uint32_t link,uint64_t entsize,uint64_t offset)84 int ELF::AddSection(const string& name, const Section& section,
85                     uint32_t type, uint32_t flags, uint64_t addr,
86                     uint32_t link, uint64_t entsize, uint64_t offset) {
87   Label offset_label;
88   Label string_label(section_header_strings_.Add(name));
89   size_t size = section.Size();
90 
91   int index = section_count_;
92   ++section_count_;
93 
94   section_header_table_
95     // sh_name
96     .D32(string_label)
97     // sh_type
98     .D32(type)
99     // sh_flags
100     .Append(endianness(), addr_size_, flags)
101     // sh_addr
102     .Append(endianness(), addr_size_, addr)
103     // sh_offset
104     .Append(endianness(), addr_size_, offset_label)
105     // sh_size
106     .Append(endianness(), addr_size_, size)
107     // sh_link
108     .D32(link)
109     // sh_info
110     .D32(0)
111     // sh_addralign
112     .Append(endianness(), addr_size_, 0)
113     // sh_entsize
114     .Append(endianness(), addr_size_, entsize);
115 
116   sections_.push_back(ElfSection(section, type, addr, offset, offset_label,
117                                  size));
118   return index;
119 }
120 
AppendSection(ElfSection & section)121 void ELF::AppendSection(ElfSection &section) {
122   // NULL and NOBITS sections have no content, so they
123   // don't need to be written to the file.
124   if (section.type_ == SHT_NULL) {
125     section.offset_label_ = 0;
126   } else if (section.type_ == SHT_NOBITS) {
127     section.offset_label_ = section.offset_;
128   } else {
129     Mark(&section.offset_label_);
130     Append(section);
131     Align(4);
132   }
133 }
134 
AddSegment(int start,int end,uint32_t type,uint32_t flags)135 void ELF::AddSegment(int start, int end, uint32_t type, uint32_t flags) {
136   assert(start > 0);
137   assert(size_t(start) < sections_.size());
138   assert(end > 0);
139   assert(size_t(end) < sections_.size());
140   ++program_count_;
141 
142   // p_type
143   program_header_table_.D32(type);
144 
145   if (addr_size_ == 8) {
146     // p_flags
147     program_header_table_.D32(flags);
148   }
149 
150   size_t filesz = 0;
151   size_t memsz = 0;
152   bool prev_was_nobits = false;
153   for (int i = start; i <= end; ++i) {
154     size_t size = sections_[i].size_;
155     if (sections_[i].type_ != SHT_NOBITS) {
156       assert(!prev_was_nobits);
157       // non SHT_NOBITS sections are 4-byte aligned (see AddSection)
158       size = (size + 3) & ~3;
159       filesz += size;
160     } else {
161       prev_was_nobits = true;
162     }
163     memsz += size;
164   }
165 
166   program_header_table_
167     // p_offset
168     .Append(endianness(), addr_size_, sections_[start].offset_label_)
169     // p_vaddr
170     .Append(endianness(), addr_size_, sections_[start].addr_)
171     // p_paddr
172     .Append(endianness(), addr_size_, sections_[start].addr_)
173     // p_filesz
174     .Append(endianness(), addr_size_, filesz)
175     // p_memsz
176     .Append(endianness(), addr_size_, memsz);
177 
178   if (addr_size_ == 4) {
179     // p_flags
180     program_header_table_.D32(flags);
181   }
182 
183   // p_align
184   program_header_table_.Append(endianness(), addr_size_, 0);
185 }
186 
Finish()187 void ELF::Finish() {
188   // Add the section header string table at the end.
189   section_header_string_index_ = section_count_;
190   //printf(".shstrtab size: %ld\n", section_header_strings_.Size());
191   AddSection(".shstrtab", section_header_strings_, SHT_STRTAB);
192   //printf("section_count_: %ld, sections_.size(): %ld\n",
193   //     section_count_, sections_.size());
194   if (program_count_) {
195     Mark(&program_header_label_);
196     Append(program_header_table_);
197   } else {
198     program_header_label_ = 0;
199   }
200 
201   for (vector<ElfSection>::iterator it = sections_.begin();
202        it < sections_.end(); ++it) {
203     AppendSection(*it);
204   }
205   section_count_label_ = section_count_;
206   program_count_label_ = program_count_;
207 
208   // Section header table starts here.
209   Mark(&section_header_label_);
210   Append(section_header_table_);
211 }
212 
SymbolTable(Endianness endianness,size_t addr_size,StringTable & table)213 SymbolTable::SymbolTable(Endianness endianness,
214                          size_t addr_size,
215                          StringTable& table) : Section(endianness),
216                                                table_(table) {
217 #ifndef NDEBUG
218   addr_size_ = addr_size;
219 #endif
220   assert(addr_size_ == 4 || addr_size_ == 8);
221 }
222 
AddSymbol(const string & name,uint32_t value,uint32_t size,unsigned info,uint16_t shndx)223 void SymbolTable::AddSymbol(const string& name, uint32_t value,
224                             uint32_t size, unsigned info, uint16_t shndx) {
225   assert(addr_size_ == 4);
226   D32(table_.Add(name));
227   D32(value);
228   D32(size);
229   D8(info);
230   D8(0); // other
231   D16(shndx);
232 }
233 
AddSymbol(const string & name,uint64_t value,uint64_t size,unsigned info,uint16_t shndx)234 void SymbolTable::AddSymbol(const string& name, uint64_t value,
235                             uint64_t size, unsigned info, uint16_t shndx) {
236   assert(addr_size_ == 8);
237   D32(table_.Add(name));
238   D8(info);
239   D8(0); // other
240   D16(shndx);
241   D64(value);
242   D64(size);
243 }
244 
AddNote(int type,const string & name,const uint8_t * desc_bytes,size_t desc_size)245 void Notes::AddNote(int type, const string &name, const uint8_t* desc_bytes,
246                     size_t desc_size) {
247   // Elf32_Nhdr and Elf64_Nhdr are exactly the same.
248   Elf32_Nhdr note_header;
249   memset(&note_header, 0, sizeof(note_header));
250   note_header.n_namesz = name.length() + 1;
251   note_header.n_descsz = desc_size;
252   note_header.n_type = type;
253 
254   Append(reinterpret_cast<const uint8_t*>(&note_header),
255          sizeof(note_header));
256   AppendCString(name);
257   Align(4);
258   Append(desc_bytes, desc_size);
259   Align(4);
260 }
261 
262 }  // namespace synth_elf
263 }  // namespace google_breakpad
264