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