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 <memory>
24#include <string.h>
25
26class ELFHeaderHelperMixin {
27protected:
28  static char const *getClassStr(int clazz);
29  static char const *getEndiannessStr(int endianness);
30  static char const *getOSABIStr(int abi);
31  static char const *getObjectTypeStr(uint16_t type);
32  static char const *getMachineStr(uint16_t machine);
33  static char const *getVersionStr(uint32_t version);
34};
35
36template <unsigned Bitwidth>
37class ELFHeader : private ELFHeaderHelperMixin {
38public:
39  ELF_TYPE_INTRO_TO_TEMPLATE_SCOPE(Bitwidth);
40
41protected:
42  byte_t   e_ident[EI_NIDENT];
43  half_t   e_type;
44  half_t   e_machine;
45  word_t   e_version;
46  addr_t   e_entry;
47  offset_t e_phoff;
48  offset_t e_shoff;
49  word_t   e_flags;
50  half_t   e_ehsize;
51  half_t   e_phentsize;
52  half_t   e_phnum;
53  half_t   e_shentsize;
54  half_t   e_shnum;
55  half_t   e_shstrndx;
56
57protected:
58  ELFHeader() { }
59
60public:
61  byte_t getClass() const {
62    return e_ident[EI_CLASS];
63  }
64
65  byte_t getEndianness() const {
66    return e_ident[EI_DATA];
67  }
68
69  byte_t getVersionFromIdent() const {
70    return e_ident[EI_VERSION];
71  }
72
73  byte_t getOSABI() const {
74    return e_ident[EI_OSABI];
75  }
76
77  byte_t getABIVersion() const {
78    return e_ident[EI_ABIVERSION];
79  }
80
81  bool is32bit() const {
82    return e_ident[EI_CLASS] == ELFCLASS32;
83  }
84
85  bool is64bit() const {
86    return e_ident[EI_CLASS] == ELFCLASS64;
87  }
88
89  bool isBigEndian() const {
90    return e_ident[EI_DATA] == ELFDATA2MSB;
91  }
92
93  bool isLittleEndian() const {
94    return e_ident[EI_DATA] == ELFDATA2LSB;
95  }
96
97  half_t getObjectType() const {
98    return e_type;
99  }
100
101  half_t getMachine() const {
102    return e_machine;
103  }
104
105  word_t getVersion() const {
106    return e_version;
107  }
108
109  addr_t getEntryAddress() const {
110    return e_entry;
111  }
112
113  offset_t getProgramHeaderTableOffset() const {
114    return e_phoff;
115  }
116
117  offset_t getSectionHeaderTableOffset() const {
118    return e_shoff;
119  }
120
121  word_t getFlags() const {
122    return e_flags;
123  }
124
125  half_t getELFHeaderSize() const {
126    return e_ehsize;
127  }
128
129  half_t getProgramHeaderEntrySize() const {
130    return e_phentsize;
131  }
132
133  half_t getProgramHeaderNum() const {
134    return e_phnum;
135  }
136
137  half_t getSectionHeaderEntrySize() const {
138    return e_shentsize;
139  }
140
141  half_t getSectionHeaderNum() const {
142    return e_shnum;
143  }
144
145  half_t getStringSectionIndex() const {
146    return e_shstrndx;
147  }
148
149  template <typename Archiver>
150  static ELFHeader *read(Archiver &AR) {
151    if (!AR) {
152      // Archiver is in bad state before calling read function.
153      // Return NULL and do nothing.
154      return 0;
155    }
156
157    std::unique_ptr<ELFHeader> header(new ELFHeader());
158    if (!header->serialize(AR)) {
159      // Unable to read the structure.  Return NULL.
160      return 0;
161    }
162
163    if (!header->isValid()) {
164      // Header read from archiver is not valid.  Return NULL.
165      return 0;
166    }
167
168    return header.release();
169  }
170
171  void print();
172
173  bool isValid() const {
174    return (isValidELFIdent() && isCompatibleHeaderSize());
175  }
176
177private:
178  template <typename Archiver>
179  bool serialize(Archiver &AR) {
180    AR.prologue(TypeTraits<ELFHeaderTy>::size);
181
182    AR & e_ident;
183    AR & e_type;
184    AR & e_machine;
185    AR & e_version;
186    AR & e_entry;
187    AR & e_phoff;
188    AR & e_shoff;
189    AR & e_flags;
190    AR & e_ehsize;
191    AR & e_phentsize;
192    AR & e_phnum;
193    AR & e_shentsize;
194    AR & e_shnum;
195    AR & e_shstrndx;
196
197    AR.epilogue(TypeTraits<ELFHeaderTy>::size);
198    return AR;
199  }
200
201  bool isValidMagicWord() const {
202    return (memcmp(e_ident, "\x7f" "ELF", 4) == 0);
203  }
204
205  bool isValidClass() const {
206    return ((Bitwidth == 32 && is32bit()) ||
207            (Bitwidth == 64 && is64bit()));
208  }
209
210  bool isValidEndianness() const {
211    return (isBigEndian() || isLittleEndian());
212  }
213
214  bool isValidHeaderVersion() const {
215    return (getVersion() == EV_CURRENT);
216  }
217
218  bool isUnusedZeroedPadding() const {
219    for (size_t i = EI_PAD; i < EI_NIDENT; ++i) {
220      if (e_ident[i] != 0) {
221        return false;
222      }
223    }
224    return true;
225  }
226
227  bool isValidELFIdent() const {
228    return (isValidMagicWord() &&
229            isValidClass() &&
230            isValidEndianness() &&
231            isValidHeaderVersion() &&
232            isUnusedZeroedPadding());
233  }
234
235  bool isCompatibleHeaderSize() const {
236    return (
237      (e_ehsize == TypeTraits<ELFHeaderTy>::size) &&
238      (e_phnum == 0 || e_phentsize == TypeTraits<ELFProgramHeaderTy>::size) &&
239      (e_shnum == 0 || e_shentsize == TypeTraits<ELFSectionHeaderTy>::size));
240  }
241};
242
243#include "impl/ELFHeader.hxx"
244
245#endif // ELF_HEADER_H
246