1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <elf.h> 18 #include <errno.h> 19 #include <fcntl.h> 20 #include <inttypes.h> 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <string.h> 24 #include <sys/mman.h> 25 #include <sys/stat.h> 26 #include <sys/types.h> 27 #include <unistd.h> 28 29 #include <unwindstack/DwarfLocation.h> 30 #include <unwindstack/DwarfMemory.h> 31 #include <unwindstack/DwarfSection.h> 32 #include <unwindstack/DwarfStructs.h> 33 #include <unwindstack/Elf.h> 34 #include <unwindstack/ElfInterface.h> 35 #include <unwindstack/Log.h> 36 37 #include "DwarfOp.h" 38 39 namespace unwindstack { 40 41 void PrintSignedValue(int64_t value) { 42 if (value < 0) { 43 printf("- %" PRId64, -value); 44 } else if (value > 0) { 45 printf("+ %" PRId64, value); 46 } 47 } 48 49 void PrintExpression(Memory* memory, uint8_t class_type, uint64_t end, uint64_t length) { 50 std::vector<std::string> lines; 51 DwarfMemory dwarf_memory(memory); 52 if (class_type == ELFCLASS32) { 53 DwarfOp<uint32_t> op(&dwarf_memory, nullptr); 54 op.GetLogInfo(end - length, end, &lines); 55 } else { 56 DwarfOp<uint64_t> op(&dwarf_memory, nullptr); 57 op.GetLogInfo(end - length, end, &lines); 58 } 59 for (auto& line : lines) { 60 printf(" %s\n", line.c_str()); 61 } 62 } 63 64 void PrintRegInformation(DwarfSection* section, Memory* memory, uint64_t pc, uint8_t class_type) { 65 const DwarfFde* fde = section->GetFdeFromPc(pc); 66 if (fde == nullptr) { 67 printf(" No fde found.\n"); 68 return; 69 } 70 71 dwarf_loc_regs_t regs; 72 if (!section->GetCfaLocationInfo(pc, fde, ®s)) { 73 printf(" Cannot get location information.\n"); 74 return; 75 } 76 77 std::vector<std::pair<uint32_t, DwarfLocation>> loc_regs; 78 for (auto& loc : regs) { 79 loc_regs.push_back(loc); 80 } 81 std::sort(loc_regs.begin(), loc_regs.end(), [](auto a, auto b) { 82 if (a.first == CFA_REG) { 83 return true; 84 } else if (b.first == CFA_REG) { 85 return false; 86 } 87 return a.first < b.first; 88 }); 89 90 for (auto& entry : loc_regs) { 91 const DwarfLocation* loc = &entry.second; 92 if (entry.first == CFA_REG) { 93 printf(" cfa = "); 94 } else { 95 printf(" r%d = ", entry.first); 96 } 97 switch (loc->type) { 98 case DWARF_LOCATION_OFFSET: 99 printf("[cfa "); 100 PrintSignedValue(loc->values[0]); 101 printf("]\n"); 102 break; 103 104 case DWARF_LOCATION_VAL_OFFSET: 105 printf("cfa "); 106 PrintSignedValue(loc->values[0]); 107 printf("\n"); 108 break; 109 110 case DWARF_LOCATION_REGISTER: 111 printf("r%" PRId64 " ", loc->values[0]); 112 PrintSignedValue(loc->values[1]); 113 printf("\n"); 114 break; 115 116 case DWARF_LOCATION_EXPRESSION: { 117 printf("EXPRESSION\n"); 118 PrintExpression(memory, class_type, loc->values[1], loc->values[0]); 119 break; 120 } 121 122 case DWARF_LOCATION_VAL_EXPRESSION: { 123 printf("VAL EXPRESSION\n"); 124 PrintExpression(memory, class_type, loc->values[1], loc->values[0]); 125 break; 126 } 127 128 case DWARF_LOCATION_UNDEFINED: 129 printf("undefine\n"); 130 break; 131 132 case DWARF_LOCATION_INVALID: 133 printf("INVALID\n"); 134 break; 135 } 136 } 137 } 138 139 int GetInfo(const char* file, uint64_t pc) { 140 MemoryFileAtOffset* memory = new MemoryFileAtOffset; 141 if (!memory->Init(file, 0)) { 142 // Initializatation failed. 143 printf("Failed to init\n"); 144 return 1; 145 } 146 147 Elf elf(memory); 148 if (!elf.Init(true) || !elf.valid()) { 149 printf("%s is not a valid elf file.\n", file); 150 return 1; 151 } 152 153 ElfInterface* interface = elf.interface(); 154 uint64_t load_bias = elf.GetLoadBias(); 155 if (pc < load_bias) { 156 printf("PC is less than load bias.\n"); 157 return 1; 158 } 159 160 std::string soname; 161 if (elf.GetSoname(&soname)) { 162 printf("Soname: %s\n\n", soname.c_str()); 163 } 164 165 printf("PC 0x%" PRIx64 ":\n", pc); 166 167 DwarfSection* section = interface->eh_frame(); 168 if (section != nullptr) { 169 printf("\neh_frame:\n"); 170 PrintRegInformation(section, memory, pc - load_bias, elf.class_type()); 171 } else { 172 printf("\nno eh_frame information\n"); 173 } 174 175 section = interface->debug_frame(); 176 if (section != nullptr) { 177 printf("\ndebug_frame:\n"); 178 PrintRegInformation(section, memory, pc - load_bias, elf.class_type()); 179 printf("\n"); 180 } else { 181 printf("\nno debug_frame information\n"); 182 } 183 184 // If there is a gnu_debugdata interface, dump the information for that. 185 ElfInterface* gnu_debugdata_interface = elf.gnu_debugdata_interface(); 186 if (gnu_debugdata_interface != nullptr) { 187 section = gnu_debugdata_interface->eh_frame(); 188 if (section != nullptr) { 189 printf("\ngnu_debugdata (eh_frame):\n"); 190 PrintRegInformation(section, gnu_debugdata_interface->memory(), pc, elf.class_type()); 191 printf("\n"); 192 } else { 193 printf("\nno gnu_debugdata (eh_frame)\n"); 194 } 195 196 section = gnu_debugdata_interface->debug_frame(); 197 if (section != nullptr) { 198 printf("\ngnu_debugdata (debug_frame):\n"); 199 PrintRegInformation(section, gnu_debugdata_interface->memory(), pc, elf.class_type()); 200 printf("\n"); 201 } else { 202 printf("\nno gnu_debugdata (debug_frame)\n"); 203 } 204 } else { 205 printf("\nno valid gnu_debugdata information\n"); 206 } 207 208 return 0; 209 } 210 211 } // namespace unwindstack 212 213 int main(int argc, char** argv) { 214 if (argc != 3) { 215 printf("Usage: unwind_reg_info ELF_FILE PC\n"); 216 printf(" ELF_FILE\n"); 217 printf(" The path to an elf file.\n"); 218 printf(" PC\n"); 219 printf(" The pc for which the register information should be obtained.\n"); 220 return 1; 221 } 222 223 struct stat st; 224 if (stat(argv[1], &st) == -1) { 225 printf("Cannot stat %s: %s\n", argv[1], strerror(errno)); 226 return 1; 227 } 228 if (!S_ISREG(st.st_mode)) { 229 printf("%s is not a regular file.\n", argv[1]); 230 return 1; 231 } 232 233 uint64_t pc = 0; 234 char* end; 235 pc = strtoull(argv[2], &end, 16); 236 if (*end != '\0') { 237 printf("Malformed OFFSET value: %s\n", argv[2]); 238 return 1; 239 } 240 241 return unwindstack::GetInfo(argv[1], pc); 242 } 243