1/*
2 * Copyright 2011, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ELF_HEADER_H
18#define ELF_HEADER_H
19
20#include "ELFTypes.h"
21#include "ELF.h"
22
23#include <llvm/ADT/OwningPtr.h>
24
25#include <string.h>
26
27class ELFHeaderHelperMixin {
28protected:
29  static char const *getClassStr(int clazz);
30  static char const *getEndiannessStr(int endianness);
31  static char const *getOSABIStr(int abi);
32  static char const *getObjectTypeStr(uint16_t type);
33  static char const *getMachineStr(uint16_t machine);
34  static char const *getVersionStr(uint32_t version);
35};
36
37template <unsigned Bitwidth>
38class ELFHeader : private ELFHeaderHelperMixin {
39public:
40  ELF_TYPE_INTRO_TO_TEMPLATE_SCOPE(Bitwidth);
41
42protected:
43  byte_t   e_ident[EI_NIDENT];
44  half_t   e_type;
45  half_t   e_machine;
46  word_t   e_version;
47  addr_t   e_entry;
48  offset_t e_phoff;
49  offset_t e_shoff;
50  word_t   e_flags;
51  half_t   e_ehsize;
52  half_t   e_phentsize;
53  half_t   e_phnum;
54  half_t   e_shentsize;
55  half_t   e_shnum;
56  half_t   e_shstrndx;
57
58protected:
59  ELFHeader() { }
60
61public:
62  byte_t getClass() const {
63    return e_ident[EI_CLASS];
64  }
65
66  byte_t getEndianness() const {
67    return e_ident[EI_DATA];
68  }
69
70  byte_t getVersionFromIdent() const {
71    return e_ident[EI_VERSION];
72  }
73
74  byte_t getOSABI() const {
75    return e_ident[EI_OSABI];
76  }
77
78  byte_t getABIVersion() const {
79    return e_ident[EI_ABIVERSION];
80  }
81
82  bool is32bit() const {
83    return e_ident[EI_CLASS] == ELFCLASS32;
84  }
85
86  bool is64bit() const {
87    return e_ident[EI_CLASS] == ELFCLASS64;
88  }
89
90  bool isBigEndian() const {
91    return e_ident[EI_DATA] == ELFDATA2MSB;
92  }
93
94  bool isLittleEndian() const {
95    return e_ident[EI_DATA] == ELFDATA2LSB;
96  }
97
98  half_t getObjectType() const {
99    return e_type;
100  }
101
102  half_t getMachine() const {
103    return e_machine;
104  }
105
106  word_t getVersion() const {
107    return e_version;
108  }
109
110  addr_t getEntryAddress() const {
111    return e_entry;
112  }
113
114  offset_t getProgramHeaderTableOffset() const {
115    return e_phoff;
116  }
117
118  offset_t getSectionHeaderTableOffset() const {
119    return e_shoff;
120  }
121
122  word_t getFlags() const {
123    return e_flags;
124  }
125
126  half_t getELFHeaderSize() const {
127    return e_ehsize;
128  }
129
130  half_t getProgramHeaderEntrySize() const {
131    return e_phentsize;
132  }
133
134  half_t getProgramHeaderNum() const {
135    return e_phnum;
136  }
137
138  half_t getSectionHeaderEntrySize() const {
139    return e_shentsize;
140  }
141
142  half_t getSectionHeaderNum() const {
143    return e_shnum;
144  }
145
146  half_t getStringSectionIndex() const {
147    return e_shstrndx;
148  }
149
150  template <typename Archiver>
151  static ELFHeader *read(Archiver &AR) {
152    if (!AR) {
153      // Archiver is in bad state before calling read function.
154      // Return NULL and do nothing.
155      return 0;
156    }
157
158    llvm::OwningPtr<ELFHeader> header(new ELFHeader());
159    if (!header->serialize(AR)) {
160      // Unable to read the structure.  Return NULL.
161      return 0;
162    }
163
164    if (!header->isValid()) {
165      // Header read from archiver is not valid.  Return NULL.
166      return 0;
167    }
168
169    return header.take();
170  }
171
172  void print();
173
174  bool isValid() const {
175    return (isValidELFIdent() && isCompatibleHeaderSize());
176  }
177
178private:
179  template <typename Archiver>
180  bool serialize(Archiver &AR) {
181    AR.prologue(TypeTraits<ELFHeaderTy>::size);
182
183    AR & e_ident;
184    AR & e_type;
185    AR & e_machine;
186    AR & e_version;
187    AR & e_entry;
188    AR & e_phoff;
189    AR & e_shoff;
190    AR & e_flags;
191    AR & e_ehsize;
192    AR & e_phentsize;
193    AR & e_phnum;
194    AR & e_shentsize;
195    AR & e_shnum;
196    AR & e_shstrndx;
197
198    AR.epilogue(TypeTraits<ELFHeaderTy>::size);
199    return AR;
200  }
201
202  bool isValidMagicWord() const {
203    return (memcmp(e_ident, "\x7f" "ELF", 4) == 0);
204  }
205
206  bool isValidClass() const {
207    return ((Bitwidth == 32 && is32bit()) ||
208            (Bitwidth == 64 && is64bit()));
209  }
210
211  bool isValidEndianness() const {
212    return (isBigEndian() || isLittleEndian());
213  }
214
215  bool isValidHeaderVersion() const {
216    return (getVersion() == EV_CURRENT);
217  }
218
219  bool isUnusedZeroedPadding() const {
220    for (size_t i = EI_PAD; i < EI_NIDENT; ++i) {
221      if (e_ident[i] != 0) {
222        return false;
223      }
224    }
225    return true;
226  }
227
228  bool isValidELFIdent() const {
229    return (isValidMagicWord() &&
230            isValidClass() &&
231            isValidEndianness() &&
232            isValidHeaderVersion() &&
233            isUnusedZeroedPadding());
234  }
235
236  bool isCompatibleHeaderSize() const {
237    return (
238      (e_ehsize == TypeTraits<ELFHeaderTy>::size) &&
239      (e_phnum == 0 || e_phentsize == TypeTraits<ELFProgramHeaderTy>::size) &&
240      (e_shnum == 0 || e_shentsize == TypeTraits<ELFSectionHeaderTy>::size));
241  }
242};
243
244#include "impl/ELFHeader.hxx"
245
246#endif // ELF_HEADER_H
247