xref: /aosp_15_r20/system/unwinding/libunwindstack/tools/unwind_info.cpp (revision eb293b8f56ee8303637c5595cfcdeef8039e85c6)
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