1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "elf.h"
6 
7 #include <elfload/elfload.h>
8 
9 #include <zircon/process.h>
10 #include <zircon/syscalls.h>
11 #include <stdlib.h>
12 
13 struct elf_load_info {
14     elf_load_header_t header;
15     elf_phdr_t phdrs[];
16 };
17 
elf_load_destroy(elf_load_info_t * info)18 void elf_load_destroy(elf_load_info_t* info) {
19     free(info);
20 }
21 
elf_load_start(zx_handle_t vmo,const void * hdr_buf,size_t buf_sz,elf_load_info_t ** infop)22 zx_status_t elf_load_start(zx_handle_t vmo, const void* hdr_buf, size_t buf_sz,
23                            elf_load_info_t** infop) {
24     elf_load_header_t header;
25     uintptr_t phoff;
26     zx_status_t status = elf_load_prepare(vmo, hdr_buf, buf_sz, &header, &phoff);
27     if (status == ZX_OK) {
28         // Now allocate the data structure and read in the phdrs.
29         size_t phdrs_size = (size_t)header.e_phnum * sizeof(elf_phdr_t);
30         elf_load_info_t* info = malloc(sizeof(*info) + phdrs_size);
31         if (info == NULL)
32             return ZX_ERR_NO_MEMORY;
33         status = elf_load_read_phdrs(vmo, info->phdrs, phoff, header.e_phnum);
34         if (status == ZX_OK) {
35             info->header = header;
36             *infop = info;
37         } else {
38             free(info);
39         }
40     }
41     return status;
42 }
43 
elf_load_get_interp(elf_load_info_t * info,zx_handle_t vmo,char ** interp,size_t * interp_len)44 zx_status_t elf_load_get_interp(elf_load_info_t* info, zx_handle_t vmo,
45                                 char** interp, size_t* interp_len) {
46     char *buffer = NULL;
47     uintptr_t offset;
48     if (elf_load_find_interp(info->phdrs, info->header.e_phnum,
49                              &offset, interp_len)) {
50         buffer = malloc(*interp_len + 1);
51         if (buffer == NULL)
52             return ZX_ERR_NO_MEMORY;
53         zx_status_t status = zx_vmo_read(vmo, buffer, offset, *interp_len);
54         if (status < 0) {
55             free(buffer);
56             return status;
57         }
58         buffer[*interp_len] = '\0';
59     }
60     *interp = buffer;
61     return ZX_OK;
62 }
63 
elf_load_finish(zx_handle_t vmar,elf_load_info_t * info,zx_handle_t vmo,zx_handle_t * segments_vmar,zx_vaddr_t * base,zx_vaddr_t * entry)64 zx_status_t elf_load_finish(zx_handle_t vmar, elf_load_info_t* info,
65                             zx_handle_t vmo,
66                             zx_handle_t* segments_vmar,
67                             zx_vaddr_t* base, zx_vaddr_t* entry) {
68     return elf_load_map_segments(vmar, &info->header, info->phdrs, vmo,
69                                  segments_vmar, base, entry);
70 }
71 
elf_load_get_stack_size(elf_load_info_t * info)72 size_t elf_load_get_stack_size(elf_load_info_t* info) {
73     for (uint_fast16_t i = 0; i < info->header.e_phnum; ++i) {
74         if (info->phdrs[i].p_type == PT_GNU_STACK)
75             return info->phdrs[i].p_memsz;
76     }
77     return 0;
78 }
79