1/*
2 * Copyright (c) 1999-2004 University of New South Wales
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <strops.h>
8#include <binaries/elf/elf.h>
9
10int
11elf64_checkFile(void *elfFile)
12{
13    struct Elf64_Header *fileHdr = (struct Elf64_Header *) elfFile;
14    if (fileHdr->e_ident[EI_MAG0] != ELFMAG0
15            || fileHdr->e_ident[EI_MAG1] != ELFMAG1
16            || fileHdr->e_ident[EI_MAG2] != ELFMAG2
17            || fileHdr->e_ident[EI_MAG3] != ELFMAG3) {
18        return -1;    /* not an elf file */
19    }
20    if (fileHdr->e_ident[EI_CLASS] != ELFCLASS64) {
21        return -2;    /* not 64-bit file */
22    }
23#if 0
24    if (fileHdr->e_ident[EI_DATA] != ELFDATA2LSB) {
25        return -3;    /* not big-endian file */
26    }
27    if (fileHdr->e_ident[EI_VERSION] != 1) {
28        return -4;    /* wrong version of elf */
29    }
30    if (fileHdr->e_machine != 8) {
31        return -5;    /* wrong architecture (not MIPS) */
32    }
33    if (fileHdr->e_type != 2) {
34        return -6;    /* not an executable program */
35    }
36    if (fileHdr->e_phentsize != sizeof(struct Elf64_Phdr)) {
37        return -7;
38    }	/* unexpected size of program segment
39				 * header */
40    if (fileHdr->e_phnum == 0) {
41        return -8;    /* no program segments */
42    }
43    if ((fileHdr->e_flags & 0x7e) != 0) {
44        return -9;
45    }	/* wrong flags (did you forgot to compile
46				 * with -mno-abicalls?) */
47#endif
48    return 0;		/* elf file looks OK */
49}
50
51struct Elf64_Phdr *
52elf64_getProgramSegmentTable(void *elfFile)
53/*
54 * Returns a pointer to the program segment table, which is an array of
55 * ELF64_Phdr_t structs.  The size of the array can be found by calling
56 * getNumProgramSegments.
57 */
58{
59    struct Elf64_Header *fileHdr = (struct Elf64_Header *) elfFile;
60    return (struct Elf64_Phdr *) ((size_t)fileHdr->e_phoff + (size_t) elfFile);
61}
62
63unsigned
64elf64_getNumSections(void *elfFile)
65/*
66 * Returns the number of program segments in this elf file.
67 */
68{
69    struct Elf64_Header *fileHdr = (struct Elf64_Header *) elfFile;
70    return fileHdr->e_shnum;
71}
72
73char           *
74elf64_getStringTable(void *elfFile, int string_segment)
75{
76    struct Elf64_Shdr *sections = elf64_getSectionTable(elfFile);
77    return (char *) elfFile + sections[string_segment].sh_offset;
78}
79
80char           *
81elf64_getSegmentStringTable(void *elfFile)
82{
83    struct Elf64_Header *fileHdr = (struct Elf64_Header *) elfFile;
84    if (fileHdr->e_shstrndx == 0) {
85        return NULL;
86    } else {
87        return elf64_getStringTable(elfFile, fileHdr->e_shstrndx);
88    }
89}
90
91char *
92elf64_getSectionName(void *elfFile, int i)
93{
94    struct Elf64_Shdr *sections = elf64_getSectionTable(elfFile);
95    char           *str_table = elf64_getSegmentStringTable(elfFile);
96    if (str_table == NULL) {
97        return "<corrupted>";
98    } else {
99        return str_table + sections[i].sh_name;
100    }
101}
102
103uint64_t
104elf64_getSectionSize(void *elfFile, int i)
105{
106    struct Elf64_Shdr *sections = elf64_getSectionTable(elfFile);
107    return sections[i].sh_size;
108}
109
110uint64_t
111elf64_getSectionAddr(struct Elf64_Header *elfFile, int i)
112{
113    struct Elf64_Shdr *sections = elf64_getSectionTable(elfFile);
114    return sections[i].sh_addr;
115}
116
117void           *
118elf64_getSection(void *elfFile, int i)
119{
120    struct Elf64_Shdr *sections = elf64_getSectionTable(elfFile);
121    return (char *)elfFile + sections[i].sh_offset;
122}
123
124void           *
125elf64_getSectionNamed(void *elfFile, char *str)
126{
127    int             numSections = elf64_getNumSections(elfFile);
128    int             i;
129    for (i = 0; i < numSections; i++) {
130        if (strcmp(str, elf64_getSectionName(elfFile, i)) == 0) {
131            return elf64_getSection(elfFile, i);
132        }
133    }
134    return NULL;
135}
136
137uint16_t
138elf64_getNumProgramHeaders(struct Elf64_Header *elfFile)
139{
140    return elfFile->e_phnum;
141}
142
143int
144elf64_getSegmentType (void *elfFile, int segment)
145{
146    return elf64_getProgramSegmentTable(elfFile)[segment].p_type;
147}
148
149void
150elf64_getSegmentInfo(void *elfFile, int segment, uint64_t *p_vaddr,
151                     uint64_t *p_paddr, uint64_t *p_filesz, uint64_t *p_offset,
152                     uint64_t *p_memsz)
153{
154    struct Elf64_Phdr *segments;
155
156    segments = elf64_getProgramSegmentTable(elfFile);
157    *p_vaddr = segments[segment].p_vaddr;
158    *p_paddr = segments[segment].p_paddr;
159    *p_filesz = segments[segment].p_filesz;
160    *p_offset = segments[segment].p_offset;
161    *p_memsz = segments[segment].p_memsz;
162}
163
164uint64_t
165elf64_getEntryPoint (struct Elf64_Header *elfFile)
166{
167    return elf64_read64(&elfFile->e_entry);
168}
169
170/*
171 * Debugging functions
172 */
173
174#if 0
175/*
176 * prints out some details of one elf file
177 */
178void
179elf64_showDetails(void *elfFile, int size, char *name)
180{
181    struct Elf64_Phdr *segments;
182    unsigned        numSegments;
183    struct Elf64_Shdr *sections;
184    unsigned        numSections;
185    int             i,
186                    r;
187    char           *str_table;
188
189    printf("Found an elf64 file called \"%s\" located "
190           "at address 0x%lx\n", name, elfFile);
191
192    if ((r = elf64_checkFile(elfFile)) != 0) {
193        char           *magic = elfFile;
194        printf("Invalid elf file (%d)\n", r);
195        printf("Magic is: %02.2hhx %02.2hhx %02.2hhx %02.2hhx\n",
196               magic[0], magic[1], magic[2], magic[3]);
197        return;
198    }
199
200    str_table = elf64_getSegmentStringTable(elfFile);
201
202    printf("Got str_table... %p\n", str_table);
203
204    /*
205     * get a pointer to the table of program segments
206     */
207    segments = elf64_getProgramSegmentTable(elfFile);
208    numSegments = elf64_getNumProgramSegments(elfFile);
209
210    sections = elf64_getSectionTable(elfFile);
211    numSections = elf64_getNumSections(elfFile);
212
213    if ((void *) sections > (void *) elfFile + size ||
214            (((uintptr_t) sections & 0xf) != 0)) {
215        printf("Corrupted elfFile..\n");
216        return;
217    }
218    printf("Sections: %p\n", sections);
219    /*
220     * print out info about each section
221     */
222
223    /*
224     * print out info about each program segment
225     */
226    printf("Program Headers:\n");
227    printf("  Type           Offset   VirtAddr   PhysAddr   "
228           "FileSiz MemSiz  Flg Align\n");
229    for (i = 0; i < numSegments; i++) {
230
231        if (segments[i].p_type != 1) {
232            printf("segment %d is not loadable, "
233                   "skipping\n", i);
234        } else {
235            printf("  LOAD           0x%06lx 0x%08lx 0x%08lx"
236                   " 0x%05lx 0x%05lx %c%c%c 0x%04lx\n",
237                   segments[i].p_offset, segments[i].p_vaddr,
238                   segments[i].p_vaddr,
239                   segments[i].p_filesz, segments[i].p_memsz,
240                   segments[i].p_flags & PF_R ? 'R' : ' ',
241                   segments[i].p_flags & PF_W ? 'W' : ' ',
242                   segments[i].p_flags & PF_X ? 'E' : ' ',
243                   segments[i].p_align);
244        }
245    }
246
247    printf("Section Headers:\n");
248    printf("  [Nr] Name              Type            Addr     Off\n");
249    for (i = 0; i < numSections; i++) {
250        if (elf_checkSection(elfFile, i) == 0) {
251            printf("%-17.17s %-15.15s %08x %06x\n", elf64_getSectionName(elfFile, i), " "	/* sections[i].sh_type
252													 */ ,
253                   sections[i].sh_addr, sections[i].sh_offset);
254        }
255    }
256}
257#endif
258