Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / android_crazy_linker / src / src / crazy_linker_elf_view.cpp
1 // Copyright 2014 The Chromium 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 "crazy_linker_elf_view.h"
6
7 #include <errno.h>
8
9 #include "crazy_linker_debug.h"
10 #include "crazy_linker_error.h"
11 #include "linker_phdr.h"
12
13 namespace crazy {
14
15 bool ElfView::InitUnmapped(ELF::Addr load_address,
16                            const ELF::Phdr* phdr,
17                            size_t phdr_count,
18                            Error* error) {
19   // Compute load size and bias.
20   ELF::Addr min_vaddr = 0;
21   load_size_ = phdr_table_get_load_size(phdr, phdr_count, &min_vaddr, NULL);
22   if (load_size_ == 0) {
23     *error = "Invalid program header table";
24     return false;
25   }
26   load_address_ = (load_address ? load_address : min_vaddr);
27   load_bias_ = load_address - min_vaddr;
28
29   // Extract the dynamic table information.
30   phdr_table_get_dynamic_section(phdr,
31                                  phdr_count,
32                                  load_bias_,
33                                  &dynamic_,
34                                  &dynamic_count_,
35                                  &dynamic_flags_);
36   if (!dynamic_) {
37     *error = "No PT_DYNAMIC section!";
38     return false;
39   }
40
41   // Compute the program header table address relative to load_address.
42   // This is different from |phdr|..|phdr + phdr_count| which can actually
43   // be at a different location.
44   const ELF::Phdr* phdr0 = NULL;
45
46   // First, if there is a PT_PHDR, use it directly.
47   for (size_t n = 0; n < phdr_count; ++n) {
48     const ELF::Phdr* entry = &phdr[n];
49     if (entry->p_type == PT_PHDR) {
50       phdr0 = entry;
51       break;
52     }
53   }
54
55   // Otherwise, check the first loadable segment. If its file offset
56   // is 0, it starts with the ELF header, and we can trivially find the
57   // loaded program header from it.
58   if (!phdr0) {
59     for (size_t n = 0; n < phdr_count; ++n) {
60       const ELF::Phdr* entry = &phdr[n];
61       if (entry->p_type == PT_LOAD) {
62         if (entry->p_offset == 0) {
63           ELF::Addr elf_addr = load_bias_ + entry->p_vaddr;
64           const ELF::Ehdr* ehdr = reinterpret_cast<const ELF::Ehdr*>(elf_addr);
65           ELF::Addr offset = ehdr->e_phoff;
66           phdr0 = reinterpret_cast<const ELF::Phdr*>(elf_addr + offset);
67         }
68         break;
69       }
70     }
71   }
72
73   // Check that the program header table is indeed in a loadable segment,
74   // this helps catching malformed ELF binaries.
75   if (phdr0) {
76     ELF::Addr phdr0_addr = reinterpret_cast<ELF::Addr>(phdr0);
77     ELF::Addr phdr0_limit = phdr0_addr + sizeof(ELF::Phdr) * phdr_count;
78     bool found = false;
79     for (size_t n = 0; n < phdr_count; ++n) {
80       size_t seg_start = load_bias_ + phdr[n].p_vaddr;
81       size_t seg_end = seg_start + phdr[n].p_filesz;
82
83       if (seg_start <= phdr0_addr && phdr0_limit <= seg_end) {
84         found = true;
85         break;
86       }
87     }
88
89     if (!found)
90       phdr0 = NULL;
91   }
92
93   if (!phdr0) {
94     *error = "Malformed ELF binary";
95     return false;
96   }
97
98   phdr_ = phdr0;
99   phdr_count_ = phdr_count;
100
101   LOG("%s: New ELF view [load_address:%p, load_size:%p, load_bias:%p, phdr:%p, "
102       "phdr_count:%d, dynamic:%p, dynamic_count:%d, dynamic_flags:%d\n",
103       __FUNCTION__,
104       load_address_,
105       load_size_,
106       load_bias_,
107       phdr_,
108       phdr_count_,
109       dynamic_,
110       dynamic_count_,
111       dynamic_flags_);
112   return true;
113 }
114
115 bool ElfView::ProtectRelroSection(Error* error) {
116   LOG("%s: Enabling GNU RELRO protection\n", __FUNCTION__);
117
118   if (phdr_table_protect_gnu_relro(phdr_, phdr_count_, load_bias_) < 0) {
119     error->Format("Can't enable GNU RELRO protection: %s", strerror(errno));
120     return false;
121   }
122   return true;
123 }
124
125 }  // namespace crazy