1*eb293b8fSAndroid Build Coastguard Worker /*
2*eb293b8fSAndroid Build Coastguard Worker * Copyright (C) 2016 The Android Open Source Project
3*eb293b8fSAndroid Build Coastguard Worker *
4*eb293b8fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*eb293b8fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*eb293b8fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*eb293b8fSAndroid Build Coastguard Worker *
8*eb293b8fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*eb293b8fSAndroid Build Coastguard Worker *
10*eb293b8fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*eb293b8fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*eb293b8fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*eb293b8fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*eb293b8fSAndroid Build Coastguard Worker * limitations under the License.
15*eb293b8fSAndroid Build Coastguard Worker */
16*eb293b8fSAndroid Build Coastguard Worker
17*eb293b8fSAndroid Build Coastguard Worker #include <elf.h>
18*eb293b8fSAndroid Build Coastguard Worker #include <errno.h>
19*eb293b8fSAndroid Build Coastguard Worker #include <fcntl.h>
20*eb293b8fSAndroid Build Coastguard Worker #include <inttypes.h>
21*eb293b8fSAndroid Build Coastguard Worker #include <stdio.h>
22*eb293b8fSAndroid Build Coastguard Worker #include <stdlib.h>
23*eb293b8fSAndroid Build Coastguard Worker #include <string.h>
24*eb293b8fSAndroid Build Coastguard Worker #include <sys/mman.h>
25*eb293b8fSAndroid Build Coastguard Worker #include <sys/stat.h>
26*eb293b8fSAndroid Build Coastguard Worker #include <sys/types.h>
27*eb293b8fSAndroid Build Coastguard Worker #include <unistd.h>
28*eb293b8fSAndroid Build Coastguard Worker
29*eb293b8fSAndroid Build Coastguard Worker #include <string>
30*eb293b8fSAndroid Build Coastguard Worker
31*eb293b8fSAndroid Build Coastguard Worker #include <unwindstack/Demangle.h>
32*eb293b8fSAndroid Build Coastguard Worker #include <unwindstack/DwarfSection.h>
33*eb293b8fSAndroid Build Coastguard Worker #include <unwindstack/DwarfStructs.h>
34*eb293b8fSAndroid Build Coastguard Worker #include <unwindstack/Elf.h>
35*eb293b8fSAndroid Build Coastguard Worker #include <unwindstack/ElfInterface.h>
36*eb293b8fSAndroid Build Coastguard Worker #include <unwindstack/Log.h>
37*eb293b8fSAndroid Build Coastguard Worker #include <unwindstack/Memory.h>
38*eb293b8fSAndroid Build Coastguard Worker
39*eb293b8fSAndroid Build Coastguard Worker #include "ArmExidx.h"
40*eb293b8fSAndroid Build Coastguard Worker #include "ElfInterfaceArm.h"
41*eb293b8fSAndroid Build Coastguard Worker
42*eb293b8fSAndroid Build Coastguard Worker namespace unwindstack {
43*eb293b8fSAndroid Build Coastguard Worker
DumpArm(Elf * elf,ElfInterfaceArm * interface)44*eb293b8fSAndroid Build Coastguard Worker void DumpArm(Elf* elf, ElfInterfaceArm* interface) {
45*eb293b8fSAndroid Build Coastguard Worker if (interface == nullptr) {
46*eb293b8fSAndroid Build Coastguard Worker printf("No ARM Unwind Information.\n\n");
47*eb293b8fSAndroid Build Coastguard Worker return;
48*eb293b8fSAndroid Build Coastguard Worker }
49*eb293b8fSAndroid Build Coastguard Worker
50*eb293b8fSAndroid Build Coastguard Worker printf("ARM Unwind Information:\n");
51*eb293b8fSAndroid Build Coastguard Worker uint64_t load_bias = elf->GetLoadBias();
52*eb293b8fSAndroid Build Coastguard Worker for (const auto& entry : interface->pt_loads()) {
53*eb293b8fSAndroid Build Coastguard Worker printf(" PC Range 0x%" PRIx64 " - 0x%" PRIx64 "\n", entry.second.offset + load_bias,
54*eb293b8fSAndroid Build Coastguard Worker entry.second.offset + entry.second.table_size + load_bias);
55*eb293b8fSAndroid Build Coastguard Worker for (auto pc : *interface) {
56*eb293b8fSAndroid Build Coastguard Worker SharedString name;
57*eb293b8fSAndroid Build Coastguard Worker printf(" PC 0x%" PRIx64, pc + load_bias);
58*eb293b8fSAndroid Build Coastguard Worker uint64_t func_offset;
59*eb293b8fSAndroid Build Coastguard Worker if (elf->GetFunctionName(pc + load_bias, &name, &func_offset) && !name.empty()) {
60*eb293b8fSAndroid Build Coastguard Worker printf(" <%s>", DemangleNameIfNeeded(name).c_str());
61*eb293b8fSAndroid Build Coastguard Worker }
62*eb293b8fSAndroid Build Coastguard Worker printf("\n");
63*eb293b8fSAndroid Build Coastguard Worker uint64_t entry;
64*eb293b8fSAndroid Build Coastguard Worker if (!interface->FindEntry(pc, &entry)) {
65*eb293b8fSAndroid Build Coastguard Worker printf(" Cannot find entry for address.\n");
66*eb293b8fSAndroid Build Coastguard Worker continue;
67*eb293b8fSAndroid Build Coastguard Worker }
68*eb293b8fSAndroid Build Coastguard Worker ArmExidx arm(nullptr, interface->memory().get(), nullptr);
69*eb293b8fSAndroid Build Coastguard Worker arm.set_log(ARM_LOG_FULL);
70*eb293b8fSAndroid Build Coastguard Worker arm.set_log_skip_execution(true);
71*eb293b8fSAndroid Build Coastguard Worker arm.set_log_indent(2);
72*eb293b8fSAndroid Build Coastguard Worker if (!arm.ExtractEntryData(entry)) {
73*eb293b8fSAndroid Build Coastguard Worker if (arm.status() != ARM_STATUS_NO_UNWIND) {
74*eb293b8fSAndroid Build Coastguard Worker printf(" Error trying to extract data.\n");
75*eb293b8fSAndroid Build Coastguard Worker }
76*eb293b8fSAndroid Build Coastguard Worker continue;
77*eb293b8fSAndroid Build Coastguard Worker }
78*eb293b8fSAndroid Build Coastguard Worker if (arm.data()->size() > 0) {
79*eb293b8fSAndroid Build Coastguard Worker if (!arm.Eval() && arm.status() != ARM_STATUS_NO_UNWIND) {
80*eb293b8fSAndroid Build Coastguard Worker printf(" Error trying to evaluate dwarf data.\n");
81*eb293b8fSAndroid Build Coastguard Worker }
82*eb293b8fSAndroid Build Coastguard Worker }
83*eb293b8fSAndroid Build Coastguard Worker }
84*eb293b8fSAndroid Build Coastguard Worker }
85*eb293b8fSAndroid Build Coastguard Worker printf("\n");
86*eb293b8fSAndroid Build Coastguard Worker }
87*eb293b8fSAndroid Build Coastguard Worker
DumpDwarfSection(Elf * elf,DwarfSection * section,uint64_t)88*eb293b8fSAndroid Build Coastguard Worker void DumpDwarfSection(Elf* elf, DwarfSection* section, uint64_t) {
89*eb293b8fSAndroid Build Coastguard Worker for (const DwarfFde* fde : *section) {
90*eb293b8fSAndroid Build Coastguard Worker // Sometimes there are entries that have empty length, skip those since
91*eb293b8fSAndroid Build Coastguard Worker // they don't contain any interesting information.
92*eb293b8fSAndroid Build Coastguard Worker if (fde == nullptr || fde->pc_start == fde->pc_end) {
93*eb293b8fSAndroid Build Coastguard Worker continue;
94*eb293b8fSAndroid Build Coastguard Worker }
95*eb293b8fSAndroid Build Coastguard Worker printf("\n PC 0x%" PRIx64 "-0x%" PRIx64, fde->pc_start, fde->pc_end);
96*eb293b8fSAndroid Build Coastguard Worker SharedString name;
97*eb293b8fSAndroid Build Coastguard Worker uint64_t func_offset;
98*eb293b8fSAndroid Build Coastguard Worker if (elf->GetFunctionName(fde->pc_start, &name, &func_offset) && !name.empty()) {
99*eb293b8fSAndroid Build Coastguard Worker printf(" <%s>", DemangleNameIfNeeded(name).c_str());
100*eb293b8fSAndroid Build Coastguard Worker }
101*eb293b8fSAndroid Build Coastguard Worker printf("\n");
102*eb293b8fSAndroid Build Coastguard Worker if (!section->Log(2, UINT64_MAX, fde, elf->arch())) {
103*eb293b8fSAndroid Build Coastguard Worker printf("Failed to process cfa information for entry at 0x%" PRIx64 "\n", fde->pc_start);
104*eb293b8fSAndroid Build Coastguard Worker }
105*eb293b8fSAndroid Build Coastguard Worker }
106*eb293b8fSAndroid Build Coastguard Worker }
107*eb293b8fSAndroid Build Coastguard Worker
GetElfInfo(const char * file,uint64_t offset)108*eb293b8fSAndroid Build Coastguard Worker int GetElfInfo(const char* file, uint64_t offset) {
109*eb293b8fSAndroid Build Coastguard Worker auto elf_memory = Memory::CreateFileMemory(file, offset);
110*eb293b8fSAndroid Build Coastguard Worker Elf elf(elf_memory);
111*eb293b8fSAndroid Build Coastguard Worker if (!elf.Init() || !elf.valid()) {
112*eb293b8fSAndroid Build Coastguard Worker printf("%s is not a valid elf file.\n", file);
113*eb293b8fSAndroid Build Coastguard Worker return 1;
114*eb293b8fSAndroid Build Coastguard Worker }
115*eb293b8fSAndroid Build Coastguard Worker
116*eb293b8fSAndroid Build Coastguard Worker std::string soname(elf.GetSoname());
117*eb293b8fSAndroid Build Coastguard Worker if (!soname.empty()) {
118*eb293b8fSAndroid Build Coastguard Worker printf("Soname: %s\n", soname.c_str());
119*eb293b8fSAndroid Build Coastguard Worker }
120*eb293b8fSAndroid Build Coastguard Worker
121*eb293b8fSAndroid Build Coastguard Worker std::string build_id = elf.GetBuildID();
122*eb293b8fSAndroid Build Coastguard Worker if (!build_id.empty()) {
123*eb293b8fSAndroid Build Coastguard Worker printf("Build ID: ");
124*eb293b8fSAndroid Build Coastguard Worker for (size_t i = 0; i < build_id.size(); ++i) {
125*eb293b8fSAndroid Build Coastguard Worker printf("%02hhx", build_id[i]);
126*eb293b8fSAndroid Build Coastguard Worker }
127*eb293b8fSAndroid Build Coastguard Worker printf("\n");
128*eb293b8fSAndroid Build Coastguard Worker }
129*eb293b8fSAndroid Build Coastguard Worker
130*eb293b8fSAndroid Build Coastguard Worker ElfInterface* interface = elf.interface();
131*eb293b8fSAndroid Build Coastguard Worker if (elf.machine_type() == EM_ARM) {
132*eb293b8fSAndroid Build Coastguard Worker DumpArm(&elf, reinterpret_cast<ElfInterfaceArm*>(interface));
133*eb293b8fSAndroid Build Coastguard Worker printf("\n");
134*eb293b8fSAndroid Build Coastguard Worker }
135*eb293b8fSAndroid Build Coastguard Worker
136*eb293b8fSAndroid Build Coastguard Worker if (interface->eh_frame() != nullptr) {
137*eb293b8fSAndroid Build Coastguard Worker printf("eh_frame information:\n");
138*eb293b8fSAndroid Build Coastguard Worker DumpDwarfSection(&elf, interface->eh_frame(), elf.GetLoadBias());
139*eb293b8fSAndroid Build Coastguard Worker printf("\n");
140*eb293b8fSAndroid Build Coastguard Worker } else {
141*eb293b8fSAndroid Build Coastguard Worker printf("\nno eh_frame information\n");
142*eb293b8fSAndroid Build Coastguard Worker }
143*eb293b8fSAndroid Build Coastguard Worker
144*eb293b8fSAndroid Build Coastguard Worker if (interface->debug_frame() != nullptr) {
145*eb293b8fSAndroid Build Coastguard Worker printf("\ndebug_frame information:\n");
146*eb293b8fSAndroid Build Coastguard Worker DumpDwarfSection(&elf, interface->debug_frame(), elf.GetLoadBias());
147*eb293b8fSAndroid Build Coastguard Worker printf("\n");
148*eb293b8fSAndroid Build Coastguard Worker } else {
149*eb293b8fSAndroid Build Coastguard Worker printf("\nno debug_frame information\n");
150*eb293b8fSAndroid Build Coastguard Worker }
151*eb293b8fSAndroid Build Coastguard Worker
152*eb293b8fSAndroid Build Coastguard Worker // If there is a gnu_debugdata interface, dump the information for that.
153*eb293b8fSAndroid Build Coastguard Worker ElfInterface* gnu_debugdata_interface = elf.gnu_debugdata_interface();
154*eb293b8fSAndroid Build Coastguard Worker if (gnu_debugdata_interface != nullptr) {
155*eb293b8fSAndroid Build Coastguard Worker if (gnu_debugdata_interface->eh_frame() != nullptr) {
156*eb293b8fSAndroid Build Coastguard Worker printf("\ngnu_debugdata (eh_frame):\n");
157*eb293b8fSAndroid Build Coastguard Worker DumpDwarfSection(&elf, gnu_debugdata_interface->eh_frame(), 0);
158*eb293b8fSAndroid Build Coastguard Worker printf("\n");
159*eb293b8fSAndroid Build Coastguard Worker }
160*eb293b8fSAndroid Build Coastguard Worker if (gnu_debugdata_interface->debug_frame() != nullptr) {
161*eb293b8fSAndroid Build Coastguard Worker printf("\ngnu_debugdata (debug_frame):\n");
162*eb293b8fSAndroid Build Coastguard Worker DumpDwarfSection(&elf, gnu_debugdata_interface->debug_frame(), 0);
163*eb293b8fSAndroid Build Coastguard Worker printf("\n");
164*eb293b8fSAndroid Build Coastguard Worker }
165*eb293b8fSAndroid Build Coastguard Worker } else {
166*eb293b8fSAndroid Build Coastguard Worker printf("\nno valid gnu_debugdata information\n");
167*eb293b8fSAndroid Build Coastguard Worker }
168*eb293b8fSAndroid Build Coastguard Worker
169*eb293b8fSAndroid Build Coastguard Worker return 0;
170*eb293b8fSAndroid Build Coastguard Worker }
171*eb293b8fSAndroid Build Coastguard Worker
172*eb293b8fSAndroid Build Coastguard Worker } // namespace unwindstack
173*eb293b8fSAndroid Build Coastguard Worker
main(int argc,char ** argv)174*eb293b8fSAndroid Build Coastguard Worker int main(int argc, char** argv) {
175*eb293b8fSAndroid Build Coastguard Worker if (argc != 2 && argc != 3) {
176*eb293b8fSAndroid Build Coastguard Worker printf("Usage: unwind_info ELF_FILE [OFFSET]\n");
177*eb293b8fSAndroid Build Coastguard Worker printf(" ELF_FILE\n");
178*eb293b8fSAndroid Build Coastguard Worker printf(" The path to an elf file.\n");
179*eb293b8fSAndroid Build Coastguard Worker printf(" OFFSET\n");
180*eb293b8fSAndroid Build Coastguard Worker printf(" Use the offset into the ELF file as the beginning of the elf.\n");
181*eb293b8fSAndroid Build Coastguard Worker return 1;
182*eb293b8fSAndroid Build Coastguard Worker }
183*eb293b8fSAndroid Build Coastguard Worker
184*eb293b8fSAndroid Build Coastguard Worker struct stat st;
185*eb293b8fSAndroid Build Coastguard Worker if (stat(argv[1], &st) == -1) {
186*eb293b8fSAndroid Build Coastguard Worker printf("Cannot stat %s: %s\n", argv[1], strerror(errno));
187*eb293b8fSAndroid Build Coastguard Worker return 1;
188*eb293b8fSAndroid Build Coastguard Worker }
189*eb293b8fSAndroid Build Coastguard Worker if (!S_ISREG(st.st_mode)) {
190*eb293b8fSAndroid Build Coastguard Worker printf("%s is not a regular file.\n", argv[1]);
191*eb293b8fSAndroid Build Coastguard Worker return 1;
192*eb293b8fSAndroid Build Coastguard Worker }
193*eb293b8fSAndroid Build Coastguard Worker
194*eb293b8fSAndroid Build Coastguard Worker uint64_t offset = 0;
195*eb293b8fSAndroid Build Coastguard Worker if (argc == 3) {
196*eb293b8fSAndroid Build Coastguard Worker char* end;
197*eb293b8fSAndroid Build Coastguard Worker offset = strtoull(argv[2], &end, 16);
198*eb293b8fSAndroid Build Coastguard Worker if (*end != '\0') {
199*eb293b8fSAndroid Build Coastguard Worker printf("Malformed OFFSET value: %s\n", argv[2]);
200*eb293b8fSAndroid Build Coastguard Worker return 1;
201*eb293b8fSAndroid Build Coastguard Worker }
202*eb293b8fSAndroid Build Coastguard Worker }
203*eb293b8fSAndroid Build Coastguard Worker
204*eb293b8fSAndroid Build Coastguard Worker return unwindstack::GetElfInfo(argv[1], offset);
205*eb293b8fSAndroid Build Coastguard Worker }
206