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
13struct elf_load_info {
14    elf_load_header_t header;
15    elf_phdr_t phdrs[];
16};
17
18void elf_load_destroy(elf_load_info_t* info) {
19    free(info);
20}
21
22zx_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
44zx_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
64zx_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
72size_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