1diff --git a/Makefile.am b/Makefile.am 2index 42386be..e8f7402 100644 3--- a/Makefile.am 4+++ b/Makefile.am 5@@ -524,6 +524,8 @@ src_tools_linux_dump_syms_dump_syms_SOURCES = \ 6 src/common/dwarf/bytereader.cc \ 7 src/common/dwarf/dwarf2diehandler.cc \ 8 src/common/dwarf/dwarf2reader.cc \ 9+ src/common/arm_ex_reader.cc \ 10+ src/common/arm_ex_to_module.cc \ 11 src/common/linux/crc32.cc \ 12 src/common/linux/dump_symbols.cc \ 13 src/common/linux/elf_symbols_to_module.cc \ 14@@ -573,6 +575,8 @@ src_tools_mac_dump_syms_dump_syms_CXXFLAGS= \ 15 -DHAVE_MACH_O_NLIST_H 16 17 src_common_dumper_unittest_SOURCES = \ 18+ src/common/arm_ex_reader.cc \ 19+ src/common/arm_ex_to_module.cc \ 20 src/common/byte_cursor_unittest.cc \ 21 src/common/dwarf_cfi_to_module.cc \ 22 src/common/dwarf_cfi_to_module_unittest.cc \ 23@@ -1336,6 +1340,10 @@ EXTRA_DIST = \ 24 src/common/linux/crc32.cc \ 25 src/common/linux/dump_symbols.cc \ 26 src/common/linux/dump_symbols.h \ 27+ src/common/arm_ex_reader.cc \ 28+ src/common/arm_ex_reader.h \ 29+ src/common/arm_ex_to_module.cc \ 30+ src/common/arm_ex_to_module.h \ 31 src/common/linux/elf_symbols_to_module.cc \ 32 src/common/linux/elf_symbols_to_module.h \ 33 src/common/linux/elfutils.cc \ 34diff --git a/src/common/arm_ex_reader.cc b/src/common/arm_ex_reader.cc 35new file mode 100644 36index 0000000..2d1ed98 37--- /dev/null 38+++ b/src/common/arm_ex_reader.cc 39@@ -0,0 +1,487 @@ 40+ 41+/* libunwind - a platform-independent unwind library 42+ Copyright 2011 Linaro Limited 43+ 44+This file is part of libunwind. 45+ 46+Permission is hereby granted, free of charge, to any person obtaining 47+a copy of this software and associated documentation files (the 48+"Software"), to deal in the Software without restriction, including 49+without limitation the rights to use, copy, modify, merge, publish, 50+distribute, sublicense, and/or sell copies of the Software, and to 51+permit persons to whom the Software is furnished to do so, subject to 52+the following conditions: 53+ 54+The above copyright notice and this permission notice shall be 55+included in all copies or substantial portions of the Software. 56+ 57+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 58+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 59+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 60+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 61+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 62+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 63+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 64+ 65+// Copyright (c) 2010 Google Inc. 66+// All rights reserved. 67+// 68+// Redistribution and use in source and binary forms, with or without 69+// modification, are permitted provided that the following conditions are 70+// met: 71+// 72+// * Redistributions of source code must retain the above copyright 73+// notice, this list of conditions and the following disclaimer. 74+// * Redistributions in binary form must reproduce the above 75+// copyright notice, this list of conditions and the following disclaimer 76+// in the documentation and/or other materials provided with the 77+// distribution. 78+// * Neither the name of Google Inc. nor the names of its 79+// contributors may be used to endorse or promote products derived from 80+// this software without specific prior written permission. 81+// 82+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 83+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 84+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 85+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 86+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 87+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 88+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 89+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 90+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 91+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 92+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 93+ 94+ 95+// Derived from libunwind, with extensive modifications. 96+ 97+ 98+#include "common/arm_ex_reader.h" 99+ 100+#include <assert.h> 101+#include <stdio.h> 102+ 103+// This file, in conjunction with arm_ex_to_module.cc, translates 104+// EXIDX unwind information into the same format that Breakpad uses 105+// for CFI information. Hence Breakpad's CFI unwinding abilities 106+// also become usable for EXIDX. 107+// 108+// See: "Exception Handling ABI for the ARM Architecture", ARM IHI 0038A 109+// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038a/IHI0038A_ehabi.pdf 110+ 111+// EXIDX data is presented in two parts: 112+// 113+// * an index table. This contains two words per routine, 114+// the first of which identifies the routine, and the second 115+// of which is a reference to the unwind bytecode. If the 116+// bytecode is very compact -- 3 bytes or less -- it can be 117+// stored directly in the second word. 118+// 119+// * an area containing the unwind bytecodes. 120+ 121+// General flow is: ExceptionTableInfo::Start iterates over all 122+// of the index table entries (pairs). For each entry, it: 123+// 124+// * calls ExceptionTableInfo::ExtabEntryExtract to copy the bytecode 125+// out into an intermediate buffer. 126+ 127+// * uses ExceptionTableInfo::ExtabEntryDecode to parse the intermediate 128+// buffer. Each bytecode instruction is bundled into a 129+// arm_ex_to_module::extab_data structure, and handed to .. 130+// 131+// * .. ARMExToModule::ImproveStackFrame, which in turn hands it to 132+// ARMExToModule::TranslateCmd, and that generates the pseudo-CFI 133+// records that Breakpad stores. 134+ 135+#define ARM_EXIDX_CANT_UNWIND 0x00000001 136+#define ARM_EXIDX_COMPACT 0x80000000 137+#define ARM_EXTBL_OP_FINISH 0xb0 138+#define ARM_EXIDX_TABLE_LIMIT (255*4) 139+ 140+namespace arm_ex_reader { 141+ 142+using arm_ex_to_module::ARM_EXIDX_CMD_FINISH; 143+using arm_ex_to_module::ARM_EXIDX_CMD_SUB_FROM_VSP; 144+using arm_ex_to_module::ARM_EXIDX_CMD_ADD_TO_VSP; 145+using arm_ex_to_module::ARM_EXIDX_CMD_REG_POP; 146+using arm_ex_to_module::ARM_EXIDX_CMD_REG_TO_SP; 147+using arm_ex_to_module::ARM_EXIDX_CMD_VFP_POP; 148+using arm_ex_to_module::ARM_EXIDX_CMD_WREG_POP; 149+using arm_ex_to_module::ARM_EXIDX_CMD_WCGR_POP; 150+using arm_ex_to_module::ARM_EXIDX_CMD_RESERVED; 151+using arm_ex_to_module::ARM_EXIDX_CMD_REFUSED; 152+using arm_ex_to_module::exidx_entry; 153+using arm_ex_to_module::ARM_EXIDX_VFP_SHIFT_16; 154+using arm_ex_to_module::ARM_EXIDX_VFP_FSTMD; 155+using google_breakpad::MemoryRange; 156+ 157+ 158+static void* Prel31ToAddr(const void* addr) { 159+ uint32_t offset32 = *reinterpret_cast<const uint32_t*>(addr); 160+ // sign extend offset32[30:0] to 64 bits -- copy bit 30 to positions 161+ // 63:31 inclusive. 162+ uint64_t offset64 = offset32; 163+ if (offset64 & (1ULL << 30)) 164+ offset64 |= 0xFFFFFFFF80000000ULL; 165+ else 166+ offset64 &= 0x000000007FFFFFFFULL; 167+ return ((char*)addr) + (uintptr_t)offset64; 168+} 169+ 170+ 171+// Extract unwind bytecode for the function denoted by |entry| into |buf|, 172+// and return the number of bytes of |buf| written, along with a code 173+// indicating the outcome. 174+ 175+ExceptionTableInfo::ExExtractResult ExceptionTableInfo::ExtabEntryExtract( 176+ const struct exidx_entry* entry, 177+ uint8_t* buf, size_t buf_size, 178+ size_t* buf_used) { 179+ MemoryRange mr_out(buf, buf_size); 180+ 181+ *buf_used = 0; 182+ 183+# define PUT_BUF_U8(_byte) \ 184+ do { if (!mr_out.Covers(*buf_used, 1)) return ExOutBufOverflow; \ 185+ buf[(*buf_used)++] = (_byte); } while (0) 186+ 187+# define GET_EX_U32(_lval, _addr, _sec_mr) \ 188+ do { if (!(_sec_mr).Covers(reinterpret_cast<const uint8_t*>(_addr) \ 189+ - (_sec_mr).data(), 4)) \ 190+ return ExInBufOverflow; \ 191+ (_lval) = *(reinterpret_cast<const uint32_t*>(_addr)); } while (0) 192+ 193+# define GET_EXIDX_U32(_lval, _addr) \ 194+ GET_EX_U32(_lval, _addr, mr_exidx_) 195+# define GET_EXTAB_U32(_lval, _addr) \ 196+ GET_EX_U32(_lval, _addr, mr_extab_) 197+ 198+ uint32_t data; 199+ GET_EXIDX_U32(data, &entry->data); 200+ 201+ // A function can be marked CANT_UNWIND if (eg) it is known to be 202+ // at the bottom of the stack. 203+ if (data == ARM_EXIDX_CANT_UNWIND) 204+ return ExCantUnwind; 205+ 206+ uint32_t pers; // personality number 207+ uint32_t extra; // number of extra data words required 208+ uint32_t extra_allowed; // number of extra data words allowed 209+ uint32_t* extbl_data; // the handler entry, if not inlined 210+ 211+ if (data & ARM_EXIDX_COMPACT) { 212+ // The handler table entry has been inlined into the index table entry. 213+ // In this case it can only be an ARM-defined compact model, since 214+ // bit 31 is 1. Only personalities 0, 1 and 2 are defined for the 215+ // ARM compact model, but 1 and 2 are "Long format" and may require 216+ // extra data words. Hence the allowable personalities here are: 217+ // personality 0, in which case 'extra' has no meaning 218+ // personality 1, with zero extra words 219+ // personality 2, with zero extra words 220+ extbl_data = NULL; 221+ pers = (data >> 24) & 0x0F; 222+ extra = (data >> 16) & 0xFF; 223+ extra_allowed = 0; 224+ } 225+ else { 226+ // The index table entry is a pointer to the handler entry. Note 227+ // that Prel31ToAddr will read the given address, but we already 228+ // range-checked above. 229+ extbl_data = reinterpret_cast<uint32_t*>(Prel31ToAddr(&entry->data)); 230+ GET_EXTAB_U32(data, extbl_data); 231+ if (!(data & ARM_EXIDX_COMPACT)) { 232+ // This denotes a "generic model" handler. That will involve 233+ // executing arbitary machine code, which is something we 234+ // can't represent here; hence reject it. 235+ return ExCantRepresent; 236+ } 237+ // So we have a compact model representation. Again, 3 possible 238+ // personalities, but this time up to 255 allowable extra words. 239+ pers = (data >> 24) & 0x0F; 240+ extra = (data >> 16) & 0xFF; 241+ extra_allowed = 255; 242+ extbl_data++; 243+ } 244+ 245+ // Now look at the the handler table entry. The first word is 246+ // |data| and subsequent words start at |*extbl_data|. The number 247+ // of extra words to use is |extra|, provided that the personality 248+ // allows extra words. Even if it does, none may be available -- 249+ // extra_allowed is the maximum number of extra words allowed. */ 250+ if (pers == 0) { 251+ // "Su16" in the documentation -- 3 unwinding insn bytes 252+ // |extra| has no meaning here; instead that byte is an unwind-info byte 253+ PUT_BUF_U8(data >> 16); 254+ PUT_BUF_U8(data >> 8); 255+ PUT_BUF_U8(data); 256+ } 257+ else if ((pers == 1 || pers == 2) && extra <= extra_allowed) { 258+ // "Lu16" or "Lu32" respectively -- 2 unwinding insn bytes, 259+ // and up to 255 extra words. 260+ PUT_BUF_U8(data >> 8); 261+ PUT_BUF_U8(data); 262+ for (uint32_t j = 0; j < extra; j++) { 263+ GET_EXTAB_U32(data, extbl_data); 264+ extbl_data++; 265+ PUT_BUF_U8(data >> 24); 266+ PUT_BUF_U8(data >> 16); 267+ PUT_BUF_U8(data >> 8); 268+ PUT_BUF_U8(data >> 0); 269+ } 270+ } 271+ else { 272+ // The entry is invalid. 273+ return ExInvalid; 274+ } 275+ 276+ // Make sure the entry is terminated with "FINISH" 277+ if (*buf_used > 0 && buf[(*buf_used) - 1] != ARM_EXTBL_OP_FINISH) 278+ PUT_BUF_U8(ARM_EXTBL_OP_FINISH); 279+ 280+ return ExSuccess; 281+ 282+# undef GET_EXTAB_U32 283+# undef GET_EXIDX_U32 284+# undef GET_U32 285+# undef PUT_BUF_U8 286+} 287+ 288+ 289+// Take the unwind information extracted by ExtabEntryExtract 290+// and parse it into frame-unwind instructions. These are as 291+// specified in "Table 4, ARM-defined frame-unwinding instructions" 292+// in the specification document detailed in comments at the top 293+// of this file. 294+// 295+// This reads from |buf[0, +data_size)|. It checks for overruns of 296+// the input buffer and returns a negative value if that happens, or 297+// for any other failure cases. It returns zero in case of success. 298+int ExceptionTableInfo::ExtabEntryDecode(const uint8_t* buf, size_t buf_size) { 299+ if (buf == NULL || buf_size == 0) 300+ return -1; 301+ 302+ MemoryRange mr_in(buf, buf_size); 303+ const uint8_t* buf_initially = buf; 304+ 305+# define GET_BUF_U8(_lval) \ 306+ do { if (!mr_in.Covers(buf - buf_initially, 1)) return -1; \ 307+ (_lval) = *(buf++); } while (0) 308+ 309+ const uint8_t* end = buf + buf_size; 310+ 311+ while (buf < end) { 312+ struct arm_ex_to_module::extab_data edata; 313+ memset(&edata, 0, sizeof(edata)); 314+ 315+ uint8_t op; 316+ GET_BUF_U8(op); 317+ if ((op & 0xc0) == 0x00) { 318+ // vsp = vsp + (xxxxxx << 2) + 4 319+ edata.cmd = ARM_EXIDX_CMD_ADD_TO_VSP; 320+ edata.data = (((int)op & 0x3f) << 2) + 4; 321+ } else if ((op & 0xc0) == 0x40) { 322+ // vsp = vsp - (xxxxxx << 2) - 4 323+ edata.cmd = ARM_EXIDX_CMD_SUB_FROM_VSP; 324+ edata.data = (((int)op & 0x3f) << 2) + 4; 325+ } else if ((op & 0xf0) == 0x80) { 326+ uint8_t op2; 327+ GET_BUF_U8(op2); 328+ if (op == 0x80 && op2 == 0x00) { 329+ // Refuse to unwind 330+ edata.cmd = ARM_EXIDX_CMD_REFUSED; 331+ } else { 332+ // Pop up to 12 integer registers under masks {r15-r12},{r11-r4} 333+ edata.cmd = ARM_EXIDX_CMD_REG_POP; 334+ edata.data = ((op & 0xf) << 8) | op2; 335+ edata.data = edata.data << 4; 336+ } 337+ } else if ((op & 0xf0) == 0x90) { 338+ if (op == 0x9d || op == 0x9f) { 339+ // 9d: Reserved as prefix for ARM register to register moves 340+ // 9f: Reserved as perfix for Intel Wireless MMX reg to reg moves 341+ edata.cmd = ARM_EXIDX_CMD_RESERVED; 342+ } else { 343+ // Set vsp = r[nnnn] 344+ edata.cmd = ARM_EXIDX_CMD_REG_TO_SP; 345+ edata.data = op & 0x0f; 346+ } 347+ } else if ((op & 0xf0) == 0xa0) { 348+ // Pop r4 to r[4+nnn], or 349+ // Pop r4 to r[4+nnn] and r14 or 350+ unsigned end = (op & 0x07); 351+ edata.data = (1 << (end + 1)) - 1; 352+ edata.data = edata.data << 4; 353+ if (op & 0x08) edata.data |= 1 << 14; 354+ edata.cmd = ARM_EXIDX_CMD_REG_POP; 355+ } else if (op == ARM_EXTBL_OP_FINISH) { 356+ // Finish 357+ edata.cmd = ARM_EXIDX_CMD_FINISH; 358+ buf = end; 359+ } else if (op == 0xb1) { 360+ uint8_t op2; 361+ GET_BUF_U8(op2); 362+ if (op2 == 0 || (op2 & 0xf0)) { 363+ // Spare 364+ edata.cmd = ARM_EXIDX_CMD_RESERVED; 365+ } else { 366+ // Pop integer registers under mask {r3,r2,r1,r0} 367+ edata.cmd = ARM_EXIDX_CMD_REG_POP; 368+ edata.data = op2 & 0x0f; 369+ } 370+ } else if (op == 0xb2) { 371+ // vsp = vsp + 0x204 + (uleb128 << 2) 372+ uint64_t offset = 0; 373+ uint8_t byte, shift = 0; 374+ do { 375+ GET_BUF_U8(byte); 376+ offset |= (byte & 0x7f) << shift; 377+ shift += 7; 378+ } while ((byte & 0x80) && buf < end); 379+ edata.data = offset * 4 + 0x204; 380+ edata.cmd = ARM_EXIDX_CMD_ADD_TO_VSP; 381+ } else if (op == 0xb3 || op == 0xc8 || op == 0xc9) { 382+ // b3: Pop VFP regs D[ssss] to D[ssss+cccc], FSTMFDX-ishly 383+ // c8: Pop VFP regs D[16+ssss] to D[16+ssss+cccc], FSTMFDD-ishly 384+ // c9: Pop VFP regs D[ssss] to D[ssss+cccc], FSTMFDD-ishly 385+ edata.cmd = ARM_EXIDX_CMD_VFP_POP; 386+ GET_BUF_U8(edata.data); 387+ if (op == 0xc8) edata.data |= ARM_EXIDX_VFP_SHIFT_16; 388+ if (op != 0xb3) edata.data |= ARM_EXIDX_VFP_FSTMD; 389+ } else if ((op & 0xf8) == 0xb8 || (op & 0xf8) == 0xd0) { 390+ // b8: Pop VFP regs D[8] to D[8+nnn], FSTMFDX-ishly 391+ // d0: Pop VFP regs D[8] to D[8+nnn], FSTMFDD-ishly 392+ edata.cmd = ARM_EXIDX_CMD_VFP_POP; 393+ edata.data = 0x80 | (op & 0x07); 394+ if ((op & 0xf8) == 0xd0) edata.data |= ARM_EXIDX_VFP_FSTMD; 395+ } else if (op >= 0xc0 && op <= 0xc5) { 396+ // Intel Wireless MMX pop wR[10]-wr[10+nnn], nnn != 6,7 397+ edata.cmd = ARM_EXIDX_CMD_WREG_POP; 398+ edata.data = 0xa0 | (op & 0x07); 399+ } else if (op == 0xc6) { 400+ // Intel Wireless MMX pop wR[ssss] to wR[ssss+cccc] 401+ edata.cmd = ARM_EXIDX_CMD_WREG_POP; 402+ GET_BUF_U8(edata.data); 403+ } else if (op == 0xc7) { 404+ uint8_t op2; 405+ GET_BUF_U8(op2); 406+ if (op2 == 0 || (op2 & 0xf0)) { 407+ // Spare 408+ edata.cmd = ARM_EXIDX_CMD_RESERVED; 409+ } else { 410+ // Intel Wireless MMX pop wCGR registers under mask {wCGR3,2,1,0} 411+ edata.cmd = ARM_EXIDX_CMD_WCGR_POP; 412+ edata.data = op2 & 0x0f; 413+ } 414+ } else { 415+ // Spare 416+ edata.cmd = ARM_EXIDX_CMD_RESERVED; 417+ } 418+ 419+ int ret = handler_->ImproveStackFrame(&edata); 420+ if (ret < 0) 421+ return ret; 422+ } 423+ return 0; 424+ 425+# undef GET_BUF_U8 426+} 427+ 428+void ExceptionTableInfo::Start() { 429+ const struct exidx_entry* start 430+ = reinterpret_cast<const struct exidx_entry*>(mr_exidx_.data()); 431+ const struct exidx_entry* end 432+ = reinterpret_cast<const struct exidx_entry*>(mr_exidx_.data() 433+ + mr_exidx_.length()); 434+ 435+ // Iterate over each of the EXIDX entries (pairs of 32-bit words). 436+ // These occupy the entire .exidx section. 437+ for (const struct exidx_entry* entry = start; entry < end; ++entry) { 438+ // Figure out the code address range that this table entry is 439+ // associated with. 440+ uint32_t addr = (reinterpret_cast<char*>(Prel31ToAddr(&entry->addr)) 441+ - mapping_addr_ + loading_addr_) & 0x7fffffff; 442+ uint32_t next_addr; 443+ if (entry < end - 1) { 444+ next_addr = (reinterpret_cast<char*>(Prel31ToAddr(&((entry + 1)->addr))) 445+ - mapping_addr_ + loading_addr_) & 0x7fffffff; 446+ } else { 447+ // This is the last EXIDX entry in the sequence, so we don't 448+ // have an address for the start of the next function, to limit 449+ // this one. Instead use the address of the last byte of the 450+ // text section associated with this .exidx section, that we 451+ // have been given. So as to avoid junking up the CFI unwind 452+ // tables with absurdly large address ranges in the case where 453+ // text_last_svma_ is wrong, only use the value if it is nonzero 454+ // and within one page of |addr|. Otherwise assume a length of 1. 455+ // 456+ // In some cases, gcc has been observed to finish the exidx 457+ // section with an entry of length 1 marked CANT_UNWIND, 458+ // presumably exactly for the purpose of giving a definite 459+ // length for the last real entry, without having to look at 460+ // text segment boundaries. 461+ bool plausible = false; 462+ next_addr = addr + 1; 463+ if (text_last_svma_ != 0) { 464+ uint32_t maybe_next_addr = text_last_svma_ + 1; 465+ if (maybe_next_addr > addr && maybe_next_addr - addr <= 4096) { 466+ next_addr = maybe_next_addr; 467+ plausible = true; 468+ } 469+ } 470+ if (!plausible) { 471+ fprintf(stderr, "ExceptionTableInfo: implausible EXIDX last entry size " 472+ "%d, using 1 instead.", (int32_t)(text_last_svma_ - addr)); 473+ } 474+ } 475+ 476+ // Extract the unwind info into |buf|. This might fail for 477+ // various reasons. It involves reading both the .exidx and 478+ // .extab sections. All accesses to those sections are 479+ // bounds-checked. 480+ uint8_t buf[ARM_EXIDX_TABLE_LIMIT]; 481+ size_t buf_used = 0; 482+ ExExtractResult res = ExtabEntryExtract(entry, buf, sizeof(buf), &buf_used); 483+ if (res != ExSuccess) { 484+ // Couldn't extract the unwind info, for some reason. Move on. 485+ switch (res) { 486+ case ExInBufOverflow: 487+ fprintf(stderr, "ExtabEntryExtract: .exidx/.extab section overrun"); 488+ break; 489+ case ExOutBufOverflow: 490+ fprintf(stderr, "ExtabEntryExtract: bytecode buffer overflow"); 491+ break; 492+ case ExCantUnwind: 493+ fprintf(stderr, "ExtabEntryExtract: function is marked CANT_UNWIND"); 494+ break; 495+ case ExCantRepresent: 496+ fprintf(stderr, "ExtabEntryExtract: bytecode can't be represented"); 497+ break; 498+ case ExInvalid: 499+ fprintf(stderr, "ExtabEntryExtract: index table entry is invalid"); 500+ break; 501+ default: 502+ fprintf(stderr, "ExtabEntryExtract: unknown error: %d", (int)res); 503+ break; 504+ } 505+ continue; 506+ } 507+ 508+ // Finally, work through the unwind instructions in |buf| and 509+ // create CFI entries that Breakpad can use. This can also fail. 510+ // First, add a new stack frame entry, into which ExtabEntryDecode 511+ // will write the CFI entries. 512+ if (!handler_->HasStackFrame(addr, next_addr - addr)) { 513+ handler_->AddStackFrame(addr, next_addr - addr); 514+ int ret = ExtabEntryDecode(buf, buf_used); 515+ if (ret < 0) { 516+ handler_->DeleteStackFrame(); 517+ fprintf(stderr, "ExtabEntryDecode: failed with error code: %d", ret); 518+ continue; 519+ } 520+ handler_->SubmitStackFrame(); 521+ } 522+ 523+ } /* iterating over .exidx */ 524+} 525+ 526+} // namespace arm_ex_reader 527diff --git a/src/common/arm_ex_reader.h b/src/common/arm_ex_reader.h 528new file mode 100644 529index 0000000..9b54e8a 530--- /dev/null 531+++ b/src/common/arm_ex_reader.h 532@@ -0,0 +1,114 @@ 533+/* libunwind - a platform-independent unwind library 534+ Copyright 2011 Linaro Limited 535+ 536+This file is part of libunwind. 537+ 538+Permission is hereby granted, free of charge, to any person obtaining 539+a copy of this software and associated documentation files (the 540+"Software"), to deal in the Software without restriction, including 541+without limitation the rights to use, copy, modify, merge, publish, 542+distribute, sublicense, and/or sell copies of the Software, and to 543+permit persons to whom the Software is furnished to do so, subject to 544+the following conditions: 545+ 546+The above copyright notice and this permission notice shall be 547+included in all copies or substantial portions of the Software. 548+ 549+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 550+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 551+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 552+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 553+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 554+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 555+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 556+ 557+// Copyright (c) 2010 Google Inc. 558+// All rights reserved. 559+// 560+// Redistribution and use in source and binary forms, with or without 561+// modification, are permitted provided that the following conditions are 562+// met: 563+// 564+// * Redistributions of source code must retain the above copyright 565+// notice, this list of conditions and the following disclaimer. 566+// * Redistributions in binary form must reproduce the above 567+// copyright notice, this list of conditions and the following disclaimer 568+// in the documentation and/or other materials provided with the 569+// distribution. 570+// * Neither the name of Google Inc. nor the names of its 571+// contributors may be used to endorse or promote products derived from 572+// this software without specific prior written permission. 573+// 574+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 575+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 576+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 577+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 578+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 579+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 580+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 581+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 582+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 583+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 584+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 585+ 586+ 587+// Derived from libunwind, with extensive modifications. 588+ 589+#ifndef COMMON_ARM_EX_READER_H__ 590+#define COMMON_ARM_EX_READER_H__ 591+ 592+#include "common/arm_ex_to_module.h" 593+#include "common/memory_range.h" 594+ 595+namespace arm_ex_reader { 596+ 597+// This class is a reader for ARM unwind information 598+// from .ARM.exidx and .ARM.extab sections. 599+class ExceptionTableInfo { 600+ public: 601+ ExceptionTableInfo(const char* exidx, size_t exidx_size, 602+ const char* extab, size_t extab_size, 603+ uint32_t text_last_svma, 604+ arm_ex_to_module::ARMExToModule* handler, 605+ const char* mapping_addr, 606+ uint32_t loading_addr) 607+ : mr_exidx_(google_breakpad::MemoryRange(exidx, exidx_size)), 608+ mr_extab_(google_breakpad::MemoryRange(extab, extab_size)), 609+ text_last_svma_(text_last_svma), 610+ handler_(handler), mapping_addr_(mapping_addr), 611+ loading_addr_(loading_addr) { } 612+ 613+ ~ExceptionTableInfo() { } 614+ 615+ // Parses the entries in .ARM.exidx and possibly 616+ // in .ARM.extab tables, reports what we find to 617+ // arm_ex_to_module::ARMExToModule. 618+ void Start(); 619+ 620+ private: 621+ google_breakpad::MemoryRange mr_exidx_; 622+ google_breakpad::MemoryRange mr_extab_; 623+ uint32_t text_last_svma_; 624+ arm_ex_to_module::ARMExToModule* handler_; 625+ const char* mapping_addr_; 626+ uint32_t loading_addr_; 627+ 628+ enum ExExtractResult { 629+ ExSuccess, // success 630+ ExInBufOverflow, // out-of-range while reading .exidx 631+ ExOutBufOverflow, // output buffer is too small 632+ ExCantUnwind, // this function is marked CANT_UNWIND 633+ ExCantRepresent, // entry valid, but we can't represent it 634+ ExInvalid // entry is invalid 635+ }; 636+ ExExtractResult 637+ ExtabEntryExtract(const struct arm_ex_to_module::exidx_entry* entry, 638+ uint8_t* buf, size_t buf_size, 639+ size_t* buf_used); 640+ 641+ int ExtabEntryDecode(const uint8_t* buf, size_t buf_size); 642+}; 643+ 644+} // namespace arm_ex_reader 645+ 646+#endif // COMMON_ARM_EX_READER_H__ 647diff --git a/src/common/arm_ex_to_module.cc b/src/common/arm_ex_to_module.cc 648new file mode 100644 649index 0000000..c326744 650--- /dev/null 651+++ b/src/common/arm_ex_to_module.cc 652@@ -0,0 +1,209 @@ 653+ 654+/* libunwind - a platform-independent unwind library 655+ Copyright 2011 Linaro Limited 656+ 657+This file is part of libunwind. 658+ 659+Permission is hereby granted, free of charge, to any person obtaining 660+a copy of this software and associated documentation files (the 661+"Software"), to deal in the Software without restriction, including 662+without limitation the rights to use, copy, modify, merge, publish, 663+distribute, sublicense, and/or sell copies of the Software, and to 664+permit persons to whom the Software is furnished to do so, subject to 665+the following conditions: 666+ 667+The above copyright notice and this permission notice shall be 668+included in all copies or substantial portions of the Software. 669+ 670+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 671+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 672+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 673+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 674+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 675+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 676+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 677+ 678+// Copyright (c) 2010 Google Inc. 679+// All rights reserved. 680+// 681+// Redistribution and use in source and binary forms, with or without 682+// modification, are permitted provided that the following conditions are 683+// met: 684+// 685+// * Redistributions of source code must retain the above copyright 686+// notice, this list of conditions and the following disclaimer. 687+// * Redistributions in binary form must reproduce the above 688+// copyright notice, this list of conditions and the following disclaimer 689+// in the documentation and/or other materials provided with the 690+// distribution. 691+// * Neither the name of Google Inc. nor the names of its 692+// contributors may be used to endorse or promote products derived from 693+// this software without specific prior written permission. 694+// 695+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 696+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 697+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 698+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 699+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 700+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 701+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 702+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 703+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 704+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 705+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 706+ 707+ 708+// Derived from libunwind, with extensive modifications. 709+ 710+#include "common/arm_ex_to_module.h" 711+ 712+#include <stdio.h> 713+#include <assert.h> 714+ 715+// For big-picture comments on how the EXIDX reader works, 716+// see arm_ex_reader.cc. 717+ 718+#define ARM_EXBUF_START(x) (((x) >> 4) & 0x0f) 719+#define ARM_EXBUF_COUNT(x) ((x) & 0x0f) 720+#define ARM_EXBUF_END(x) (ARM_EXBUF_START(x) + ARM_EXBUF_COUNT(x)) 721+ 722+using google_breakpad::Module; 723+ 724+namespace arm_ex_to_module { 725+ 726+static const char* const regnames[] = { 727+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", 728+ "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc", 729+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", 730+ "fps", "cpsr" 731+}; 732+ 733+// Translate command from extab_data to command for Module. 734+int ARMExToModule::TranslateCmd(const struct extab_data* edata, 735+ Module::StackFrameEntry* entry, string& vsp) { 736+ int ret = 0; 737+ switch (edata->cmd) { 738+ case ARM_EXIDX_CMD_FINISH: 739+ /* Copy LR to PC if there isn't currently a rule for PC in force. */ 740+ if (entry->initial_rules.find("pc") 741+ == entry->initial_rules.end()) { 742+ if (entry->initial_rules.find("lr") 743+ == entry->initial_rules.end()) { 744+ entry->initial_rules["pc"] = "lr"; 745+ } else { 746+ entry->initial_rules["pc"] = entry->initial_rules["lr"]; 747+ } 748+ } 749+ break; 750+ case ARM_EXIDX_CMD_SUB_FROM_VSP: 751+ { 752+ char c[16]; 753+ sprintf(c, " %d -", edata->data); 754+ vsp += c; 755+ } 756+ break; 757+ case ARM_EXIDX_CMD_ADD_TO_VSP: 758+ { 759+ char c[16]; 760+ sprintf(c, " %d +", edata->data); 761+ vsp += c; 762+ } 763+ break; 764+ case ARM_EXIDX_CMD_REG_POP: 765+ for (unsigned int i = 0; i < 16; i++) { 766+ if (edata->data & (1 << i)) { 767+ entry->initial_rules[regnames[i]] 768+ = vsp + " ^"; 769+ vsp += " 4 +"; 770+ } 771+ } 772+ /* Set cfa in case the SP got popped. */ 773+ if (edata->data & (1 << 13)) { 774+ vsp = entry->initial_rules["sp"]; 775+ } 776+ break; 777+ case ARM_EXIDX_CMD_REG_TO_SP: { 778+ assert (edata->data < 16); 779+ const char* const regname = regnames[edata->data]; 780+ if (entry->initial_rules.find(regname) == entry->initial_rules.end()) { 781+ entry->initial_rules["sp"] = regname; 782+ } else { 783+ entry->initial_rules["sp"] = entry->initial_rules[regname]; 784+ } 785+ vsp = entry->initial_rules["sp"]; 786+ break; 787+ } 788+ case ARM_EXIDX_CMD_VFP_POP: 789+ /* Don't recover VFP registers, but be sure to adjust the stack 790+ pointer. */ 791+ for (unsigned int i = ARM_EXBUF_START(edata->data); 792+ i <= ARM_EXBUF_END(edata->data); i++) { 793+ vsp += " 8 +"; 794+ } 795+ if (!(edata->data & ARM_EXIDX_VFP_FSTMD)) { 796+ vsp += " 4 +"; 797+ } 798+ break; 799+ case ARM_EXIDX_CMD_WREG_POP: 800+ for (unsigned int i = ARM_EXBUF_START(edata->data); 801+ i <= ARM_EXBUF_END(edata->data); i++) { 802+ vsp += " 8 +"; 803+ } 804+ break; 805+ case ARM_EXIDX_CMD_WCGR_POP: 806+ // Pop wCGR registers under mask {wCGR3,2,1,0}, hence "i < 4" 807+ for (unsigned int i = 0; i < 4; i++) { 808+ if (edata->data & (1 << i)) { 809+ vsp += " 4 +"; 810+ } 811+ } 812+ break; 813+ case ARM_EXIDX_CMD_REFUSED: 814+ case ARM_EXIDX_CMD_RESERVED: 815+ ret = -1; 816+ break; 817+ } 818+ return ret; 819+} 820+ 821+bool ARMExToModule::HasStackFrame(uintptr_t addr, size_t size) { 822+ // Invariant: the range [addr,covered) is covered by existing stack 823+ // frame entries. 824+ uintptr_t covered = addr; 825+ while (covered < addr + size) { 826+ const Module::StackFrameEntry *old_entry = 827+ module_->FindStackFrameEntryByAddress(covered); 828+ if (!old_entry) { 829+ return false; 830+ } 831+ covered = old_entry->address + old_entry->size; 832+ } 833+ return true; 834+} 835+ 836+void ARMExToModule::AddStackFrame(uintptr_t addr, size_t size) { 837+ stack_frame_entry_ = new Module::StackFrameEntry; 838+ stack_frame_entry_->address = addr; 839+ stack_frame_entry_->size = size; 840+ stack_frame_entry_->initial_rules[".cfa"] = "sp"; 841+ vsp_ = "sp"; 842+} 843+ 844+int ARMExToModule::ImproveStackFrame(const struct extab_data* edata) { 845+ return TranslateCmd(edata, stack_frame_entry_, vsp_) ; 846+} 847+ 848+void ARMExToModule::DeleteStackFrame() { 849+ delete stack_frame_entry_; 850+} 851+ 852+void ARMExToModule::SubmitStackFrame() { 853+ // return address always winds up in pc 854+ stack_frame_entry_->initial_rules[".ra"] 855+ = stack_frame_entry_->initial_rules["pc"]; 856+ // the final value of vsp is the new value of sp 857+ stack_frame_entry_->initial_rules["sp"] = vsp_; 858+ module_->AddStackFrameEntry(stack_frame_entry_); 859+} 860+ 861+} // namespace arm_ex_to_module 862diff --git a/src/common/arm_ex_to_module.h b/src/common/arm_ex_to_module.h 863new file mode 100644 864index 0000000..f413a16 865--- /dev/null 866+++ b/src/common/arm_ex_to_module.h 867@@ -0,0 +1,119 @@ 868+/* libunwind - a platform-independent unwind library 869+ Copyright 2011 Linaro Limited 870+ 871+This file is part of libunwind. 872+ 873+Permission is hereby granted, free of charge, to any person obtaining 874+a copy of this software and associated documentation files (the 875+"Software"), to deal in the Software without restriction, including 876+without limitation the rights to use, copy, modify, merge, publish, 877+distribute, sublicense, and/or sell copies of the Software, and to 878+permit persons to whom the Software is furnished to do so, subject to 879+the following conditions: 880+ 881+The above copyright notice and this permission notice shall be 882+included in all copies or substantial portions of the Software. 883+ 884+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 885+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 886+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 887+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 888+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 889+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 890+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 891+ 892+// Copyright (c) 2010 Google Inc. 893+// All rights reserved. 894+// 895+// Redistribution and use in source and binary forms, with or without 896+// modification, are permitted provided that the following conditions are 897+// met: 898+// 899+// * Redistributions of source code must retain the above copyright 900+// notice, this list of conditions and the following disclaimer. 901+// * Redistributions in binary form must reproduce the above 902+// copyright notice, this list of conditions and the following disclaimer 903+// in the documentation and/or other materials provided with the 904+// distribution. 905+// * Neither the name of Google Inc. nor the names of its 906+// contributors may be used to endorse or promote products derived from 907+// this software without specific prior written permission. 908+// 909+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 910+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 911+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 912+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 913+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 914+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 915+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 916+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 917+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 918+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 919+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 920+ 921+ 922+// Derived from libunwind, with extensive modifications. 923+ 924+#ifndef COMMON_ARM_EX_TO_MODULE__ 925+#define COMMON_ARM_EX_TO_MODULE__ 926+ 927+#include "common/module.h" 928+ 929+#include <string.h> 930+ 931+namespace arm_ex_to_module { 932+ 933+using google_breakpad::Module; 934+ 935+typedef enum extab_cmd { 936+ ARM_EXIDX_CMD_FINISH, 937+ ARM_EXIDX_CMD_SUB_FROM_VSP, 938+ ARM_EXIDX_CMD_ADD_TO_VSP, 939+ ARM_EXIDX_CMD_REG_POP, 940+ ARM_EXIDX_CMD_REG_TO_SP, 941+ ARM_EXIDX_CMD_VFP_POP, 942+ ARM_EXIDX_CMD_WREG_POP, 943+ ARM_EXIDX_CMD_WCGR_POP, 944+ ARM_EXIDX_CMD_RESERVED, 945+ ARM_EXIDX_CMD_REFUSED, 946+} extab_cmd_t; 947+ 948+struct exidx_entry { 949+ uint32_t addr; 950+ uint32_t data; 951+}; 952+ 953+struct extab_data { 954+ extab_cmd_t cmd; 955+ uint32_t data; 956+}; 957+ 958+enum extab_cmd_flags { 959+ ARM_EXIDX_VFP_SHIFT_16 = 1 << 16, 960+ ARM_EXIDX_VFP_FSTMD = 1 << 17, // distinguishes FSTMxxD from FSTMxxX 961+}; 962+ 963+// Receives information from arm_ex_reader::ExceptionTableInfo 964+// and adds it to the Module object 965+class ARMExToModule { 966+ public: 967+ ARMExToModule(Module* module) 968+ : module_(module) { } 969+ ~ARMExToModule() { } 970+ bool HasStackFrame(uintptr_t addr, size_t size); 971+ void AddStackFrame(uintptr_t addr, size_t size); 972+ int ImproveStackFrame(const struct extab_data* edata); 973+ void DeleteStackFrame(); 974+ void SubmitStackFrame(); 975+ private: 976+ Module* module_; 977+ Module::StackFrameEntry* stack_frame_entry_; 978+ string vsp_; 979+ int TranslateCmd(const struct extab_data* edata, 980+ Module::StackFrameEntry* entry, 981+ string& vsp); 982+}; 983+ 984+} // namespace arm_ex_to_module 985+ 986+#endif // COMMON_ARM_EX_TO_MODULE__ 987diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc 988index 1e96ca6..4222ce3 100644 989--- a/src/common/linux/dump_symbols.cc 990+++ b/src/common/linux/dump_symbols.cc 991@@ -52,6 +52,7 @@ 992 #include <utility> 993 #include <vector> 994 995+#include "common/arm_ex_reader.h" 996 #include "common/dwarf/bytereader-inl.h" 997 #include "common/dwarf/dwarf2diehandler.h" 998 #include "common/dwarf_cfi_to_module.h" 999@@ -71,6 +72,11 @@ 1000 #endif 1001 #include "common/using_std_string.h" 1002 1003+#ifndef SHT_ARM_EXIDX 1004+// bionic and older glibc don't define this 1005+# define SHT_ARM_EXIDX (SHT_LOPROC + 1) 1006+#endif 1007+ 1008 // This namespace contains helper functions. 1009 namespace { 1010 1011@@ -373,6 +379,52 @@ bool LoadDwarfCFI(const string& dwarf_filename, 1012 return true; 1013 } 1014 1015+template<typename ElfClass> 1016+bool LoadARMexidx(const typename ElfClass::Ehdr* elf_header, 1017+ const typename ElfClass::Shdr* exidx_section, 1018+ const typename ElfClass::Shdr* extab_section, 1019+ uint32_t loading_addr, 1020+ Module* module) { 1021+ // To do this properly we need to know: 1022+ // * the bounds of the .ARM.exidx section in the mapped image 1023+ // * the bounds of the .ARM.extab section in the mapped image 1024+ // * the vma of the last byte in the text section associated with the .exidx 1025+ // The first two are easy. The third is a bit tricky. If we can't 1026+ // figure out what it is, just pass in zero. 1027+ const char *exidx_img 1028+ = GetOffset<ElfClass, char>(elf_header, exidx_section->sh_offset); 1029+ size_t exidx_size = exidx_section->sh_size; 1030+ const char *extab_img 1031+ = GetOffset<ElfClass, char>(elf_header, extab_section->sh_offset); 1032+ size_t extab_size = extab_section->sh_size; 1033+ 1034+ // The sh_link field of the exidx section gives the section number 1035+ // for the associated text section. 1036+ uint32_t exidx_text_last_svma = 0; 1037+ int exidx_text_sno = exidx_section->sh_link; 1038+ typedef typename ElfClass::Shdr Shdr; 1039+ // |sections| points to the section header table 1040+ const Shdr* sections 1041+ = GetOffset<ElfClass, Shdr>(elf_header, elf_header->e_shoff); 1042+ const int num_sections = elf_header->e_shnum; 1043+ if (exidx_text_sno >= 0 && exidx_text_sno < num_sections) { 1044+ const Shdr* exidx_text_shdr = §ions[exidx_text_sno]; 1045+ if (exidx_text_shdr->sh_size > 0) { 1046+ exidx_text_last_svma 1047+ = exidx_text_shdr->sh_addr + exidx_text_shdr->sh_size - 1; 1048+ } 1049+ } 1050+ 1051+ arm_ex_to_module::ARMExToModule handler(module); 1052+ arm_ex_reader::ExceptionTableInfo 1053+ parser(exidx_img, exidx_size, extab_img, extab_size, exidx_text_last_svma, 1054+ &handler, 1055+ reinterpret_cast<const char*>(elf_header), 1056+ loading_addr); 1057+ parser.Start(); 1058+ return true; 1059+} 1060+ 1061 bool LoadELF(const string& obj_file, MmapWrapper* map_wrapper, 1062 void** elf_header) { 1063 int obj_fd = open(obj_file.c_str(), O_RDONLY); 1064@@ -756,6 +808,29 @@ bool LoadSymbols(const string& obj_file, 1065 } 1066 } 1067 1068+ // ARM has special unwind tables that can be used. 1069+ const Shdr* arm_exidx_section = 1070+ FindElfSectionByName<ElfClass>(".ARM.exidx", SHT_ARM_EXIDX, 1071+ sections, names, names_end, 1072+ elf_header->e_shnum); 1073+ const Shdr* arm_extab_section = 1074+ FindElfSectionByName<ElfClass>(".ARM.extab", SHT_PROGBITS, 1075+ sections, names, names_end, 1076+ elf_header->e_shnum); 1077+ // Load information from these sections even if there is 1078+ // .debug_info, because some functions (e.g., hand-written or 1079+ // script-generated assembly) could have exidx entries but no DWARF. 1080+ // (For functions with both, the DWARF info that has already been 1081+ // parsed will take precedence.) 1082+ if (arm_exidx_section && arm_extab_section && options.symbol_data != NO_CFI) { 1083+ info->LoadedSection(".ARM.exidx"); 1084+ info->LoadedSection(".ARM.extab"); 1085+ bool result = LoadARMexidx<ElfClass>(elf_header, 1086+ arm_exidx_section, arm_extab_section, 1087+ loading_addr, module); 1088+ found_usable_info = found_usable_info || result; 1089+ } 1090+ 1091 if (!found_debug_info_section) { 1092 fprintf(stderr, "%s: file contains no debugging information" 1093 " (no \".stab\" or \".debug_info\" sections)\n", 1094diff --git a/src/common/module.cc b/src/common/module.cc 1095index fa798f4..ca52f9f 100644 1096--- a/src/common/module.cc 1097+++ b/src/common/module.cc 1098@@ -63,7 +63,7 @@ Module::~Module() { 1099 it != functions_.end(); ++it) { 1100 delete *it; 1101 } 1102- for (vector<StackFrameEntry *>::iterator it = stack_frame_entries_.begin(); 1103+ for (StackFrameEntrySet::iterator it = stack_frame_entries_.begin(); 1104 it != stack_frame_entries_.end(); ++it) { 1105 delete *it; 1106 } 1107@@ -119,8 +119,14 @@ void Module::AddFunctions(vector<Function *>::iterator begin, 1108 AddFunction(*it); 1109 } 1110 1111-void Module::AddStackFrameEntry(StackFrameEntry *stack_frame_entry) { 1112- stack_frame_entries_.push_back(stack_frame_entry); 1113+void Module::AddStackFrameEntry(StackFrameEntry* stack_frame_entry) { 1114+ std::pair<StackFrameEntrySet::iterator,bool> ret = 1115+ stack_frame_entries_.insert(stack_frame_entry); 1116+ if (!ret.second) { 1117+ // Free the duplicate that was not inserted because this Module 1118+ // now owns it. 1119+ delete stack_frame_entry; 1120+ } 1121 } 1122 1123 void Module::AddExtern(Extern *ext) { 1124@@ -180,8 +186,25 @@ void Module::GetFiles(vector<File *> *vec) { 1125 vec->push_back(it->second); 1126 } 1127 1128-void Module::GetStackFrameEntries(vector<StackFrameEntry *> *vec) const { 1129- *vec = stack_frame_entries_; 1130+void Module::GetStackFrameEntries(vector<StackFrameEntry*>* vec) const { 1131+ vec->clear(); 1132+ vec->insert(vec->begin(), stack_frame_entries_.begin(), 1133+ stack_frame_entries_.end()); 1134+} 1135+ 1136+Module::StackFrameEntry* Module::FindStackFrameEntryByAddress(Address address) { 1137+ StackFrameEntry search; 1138+ search.address = address; 1139+ StackFrameEntrySet::iterator it = stack_frame_entries_.upper_bound(&search); 1140+ 1141+ if (it == stack_frame_entries_.begin()) 1142+ return NULL; 1143+ 1144+ it--; 1145+ if ((*it)->address <= address && address < (*it)->address + (*it)->size) 1146+ return *it; 1147+ 1148+ return NULL; 1149 } 1150 1151 void Module::AssignSourceIds() { 1152@@ -286,7 +309,7 @@ bool Module::Write(std::ostream &stream, SymbolData symbol_data) { 1153 1154 if (symbol_data != NO_CFI) { 1155 // Write out 'STACK CFI INIT' and 'STACK CFI' records. 1156- vector<StackFrameEntry *>::const_iterator frame_it; 1157+ StackFrameEntrySet::const_iterator frame_it; 1158 for (frame_it = stack_frame_entries_.begin(); 1159 frame_it != stack_frame_entries_.end(); ++frame_it) { 1160 StackFrameEntry *entry = *frame_it; 1161diff --git a/src/common/module.h b/src/common/module.h 1162index 65b5595..299bc38 100644 1163--- a/src/common/module.h 1164+++ b/src/common/module.h 1165@@ -176,6 +176,13 @@ class Module { 1166 } 1167 }; 1168 1169+ struct StackFrameEntryCompare { 1170+ bool operator() (const StackFrameEntry* lhs, 1171+ const StackFrameEntry* rhs) const { 1172+ return lhs->address < rhs->address; 1173+ } 1174+ }; 1175+ 1176 // Create a new module with the given name, operating system, 1177 // architecture, and ID string. 1178 Module(const string &name, const string &os, const string &architecture, 1179@@ -256,6 +263,10 @@ class Module { 1180 // a more appropriate interface.) 1181 void GetStackFrameEntries(vector<StackFrameEntry *> *vec) const; 1182 1183+ // If this module has a StackFrameEntry whose address range covers 1184+ // ADDRESS, return it. Otherwise return NULL. 1185+ StackFrameEntry* FindStackFrameEntryByAddress(Address address); 1186+ 1187 // Find those files in this module that are actually referred to by 1188 // functions' line number data, and assign them source id numbers. 1189 // Set the source id numbers for all other files --- unused by the 1190@@ -316,6 +327,9 @@ class Module { 1191 // A set containing Extern structures, sorted by address. 1192 typedef set<Extern *, ExternCompare> ExternSet; 1193 1194+ // A set containing StackFrameEntry structures, sorted by address. 1195+ typedef set<StackFrameEntry*, StackFrameEntryCompare> StackFrameEntrySet; 1196+ 1197 // The module owns all the files and functions that have been added 1198 // to it; destroying the module frees the Files and Functions these 1199 // point to. 1200@@ -324,7 +338,7 @@ class Module { 1201 1202 // The module owns all the call frame info entries that have been 1203 // added to it. 1204- vector<StackFrameEntry *> stack_frame_entries_; 1205+ StackFrameEntrySet stack_frame_entries_; 1206 1207 // The module owns all the externs that have been added to it; 1208 // destroying the module frees the Externs these point to. 1209diff --git a/src/common/module_unittest.cc b/src/common/module_unittest.cc 1210index 0b64327..bf72736 100644 1211--- a/src/common/module_unittest.cc 1212+++ b/src/common/module_unittest.cc 1213@@ -326,11 +326,6 @@ TEST(Construct, AddFrames) { 1214 m.Write(s, ALL_SYMBOL_DATA); 1215 string contents = s.str(); 1216 EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" 1217- "STACK CFI INIT ddb5f41285aa7757 1486493370dc5073 \n" 1218- "STACK CFI INIT 8064f3af5e067e38 de2a5ee55509407" 1219- " .cfa: I think that I shall never see" 1220- " cannoli: a tree whose hungry mouth is prest" 1221- " stromboli: a poem lovely as a tree\n" 1222 "STACK CFI INIT 5e8d0db0a7075c6c 1c7edb12a7aea229" 1223 " .cfa: Whose woods are these\n" 1224 "STACK CFI 36682fad3763ffff" 1225@@ -338,7 +333,12 @@ TEST(Construct, AddFrames) { 1226 " stromboli: his house is in\n" 1227 "STACK CFI 47ceb0f63c269d7f" 1228 " calzone: the village though" 1229- " cannoli: he will not see me stopping here\n", 1230+ " cannoli: he will not see me stopping here\n" 1231+ "STACK CFI INIT 8064f3af5e067e38 de2a5ee55509407" 1232+ " .cfa: I think that I shall never see" 1233+ " cannoli: a tree whose hungry mouth is prest" 1234+ " stromboli: a poem lovely as a tree\n" 1235+ "STACK CFI INIT ddb5f41285aa7757 1486493370dc5073 \n", 1236 contents.c_str()); 1237 1238 // Check that GetStackFrameEntries works. 1239@@ -346,10 +346,18 @@ TEST(Construct, AddFrames) { 1240 m.GetStackFrameEntries(&entries); 1241 ASSERT_EQ(3U, entries.size()); 1242 // Check first entry. 1243- EXPECT_EQ(0xddb5f41285aa7757ULL, entries[0]->address); 1244- EXPECT_EQ(0x1486493370dc5073ULL, entries[0]->size); 1245- ASSERT_EQ(0U, entries[0]->initial_rules.size()); 1246- ASSERT_EQ(0U, entries[0]->rule_changes.size()); 1247+ EXPECT_EQ(0x5e8d0db0a7075c6cULL, entries[0]->address); 1248+ EXPECT_EQ(0x1c7edb12a7aea229ULL, entries[0]->size); 1249+ Module::RuleMap entry1_initial; 1250+ entry1_initial[".cfa"] = "Whose woods are these"; 1251+ EXPECT_THAT(entries[0]->initial_rules, ContainerEq(entry1_initial)); 1252+ Module::RuleChangeMap entry1_changes; 1253+ entry1_changes[0x36682fad3763ffffULL][".cfa"] = "I think I know"; 1254+ entry1_changes[0x36682fad3763ffffULL]["stromboli"] = "his house is in"; 1255+ entry1_changes[0x47ceb0f63c269d7fULL]["calzone"] = "the village though"; 1256+ entry1_changes[0x47ceb0f63c269d7fULL]["cannoli"] = 1257+ "he will not see me stopping here"; 1258+ EXPECT_THAT(entries[0]->rule_changes, ContainerEq(entry1_changes)); 1259 // Check second entry. 1260 EXPECT_EQ(0x8064f3af5e067e38ULL, entries[1]->address); 1261 EXPECT_EQ(0x0de2a5ee55509407ULL, entries[1]->size); 1262@@ -361,18 +369,10 @@ TEST(Construct, AddFrames) { 1263 EXPECT_THAT(entries[1]->initial_rules, ContainerEq(entry2_initial)); 1264 ASSERT_EQ(0U, entries[1]->rule_changes.size()); 1265 // Check third entry. 1266- EXPECT_EQ(0x5e8d0db0a7075c6cULL, entries[2]->address); 1267- EXPECT_EQ(0x1c7edb12a7aea229ULL, entries[2]->size); 1268- Module::RuleMap entry3_initial; 1269- entry3_initial[".cfa"] = "Whose woods are these"; 1270- EXPECT_THAT(entries[2]->initial_rules, ContainerEq(entry3_initial)); 1271- Module::RuleChangeMap entry3_changes; 1272- entry3_changes[0x36682fad3763ffffULL][".cfa"] = "I think I know"; 1273- entry3_changes[0x36682fad3763ffffULL]["stromboli"] = "his house is in"; 1274- entry3_changes[0x47ceb0f63c269d7fULL]["calzone"] = "the village though"; 1275- entry3_changes[0x47ceb0f63c269d7fULL]["cannoli"] = 1276- "he will not see me stopping here"; 1277- EXPECT_THAT(entries[2]->rule_changes, ContainerEq(entry3_changes)); 1278+ EXPECT_EQ(0xddb5f41285aa7757ULL, entries[2]->address); 1279+ EXPECT_EQ(0x1486493370dc5073ULL, entries[2]->size); 1280+ ASSERT_EQ(0U, entries[2]->initial_rules.size()); 1281+ ASSERT_EQ(0U, entries[2]->rule_changes.size()); 1282 } 1283 1284 TEST(Construct, UniqueFiles) { 1285@@ -544,3 +544,62 @@ TEST(Construct, FunctionsAndThumbExternsWithSameAddress) { 1286 "PUBLIC cc00 0 arm_func\n", 1287 contents.c_str()); 1288 } 1289+ 1290+TEST(Lookup, StackFrameEntries) { 1291+ Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); 1292+ 1293+ // First STACK CFI entry, with no initial rules or deltas. 1294+ Module::StackFrameEntry *entry1 = new Module::StackFrameEntry(); 1295+ entry1->address = 0x2000; 1296+ entry1->size = 0x900; 1297+ m.AddStackFrameEntry(entry1); 1298+ 1299+ // Second STACK CFI entry, with initial rules but no deltas. 1300+ Module::StackFrameEntry *entry2 = new Module::StackFrameEntry(); 1301+ entry2->address = 0x3000; 1302+ entry2->size = 0x900; 1303+ entry2->initial_rules[".cfa"] = "I think that I shall never see"; 1304+ entry2->initial_rules["stromboli"] = "a poem lovely as a tree"; 1305+ entry2->initial_rules["cannoli"] = "a tree whose hungry mouth is prest"; 1306+ m.AddStackFrameEntry(entry2); 1307+ 1308+ // Third STACK CFI entry, with initial rules and deltas. 1309+ Module::StackFrameEntry *entry3 = new Module::StackFrameEntry(); 1310+ entry3->address = 0x1000; 1311+ entry3->size = 0x900; 1312+ entry3->initial_rules[".cfa"] = "Whose woods are these"; 1313+ entry3->rule_changes[0x47ceb0f63c269d7fULL]["calzone"] = 1314+ "the village though"; 1315+ entry3->rule_changes[0x47ceb0f63c269d7fULL]["cannoli"] = 1316+ "he will not see me stopping here"; 1317+ entry3->rule_changes[0x36682fad3763ffffULL]["stromboli"] = 1318+ "his house is in"; 1319+ entry3->rule_changes[0x36682fad3763ffffULL][".cfa"] = 1320+ "I think I know"; 1321+ m.AddStackFrameEntry(entry3); 1322+ 1323+ Module::StackFrameEntry* s = m.FindStackFrameEntryByAddress(0x1000); 1324+ EXPECT_EQ(entry3, s); 1325+ s = m.FindStackFrameEntryByAddress(0x18FF); 1326+ EXPECT_EQ(entry3, s); 1327+ 1328+ s = m.FindStackFrameEntryByAddress(0x1900); 1329+ EXPECT_EQ((Module::StackFrameEntry*)NULL, s); 1330+ s = m.FindStackFrameEntryByAddress(0x1A00); 1331+ EXPECT_EQ((Module::StackFrameEntry*)NULL, s); 1332+ 1333+ s = m.FindStackFrameEntryByAddress(0x2000); 1334+ EXPECT_EQ(entry1, s); 1335+ s = m.FindStackFrameEntryByAddress(0x28FF); 1336+ EXPECT_EQ(entry1, s); 1337+ 1338+ s = m.FindStackFrameEntryByAddress(0x3000); 1339+ EXPECT_EQ(entry2, s); 1340+ s = m.FindStackFrameEntryByAddress(0x38FF); 1341+ EXPECT_EQ(entry2, s); 1342+ 1343+ s = m.FindStackFrameEntryByAddress(0x3900); 1344+ EXPECT_EQ((Module::StackFrameEntry*)NULL, s); 1345+ s = m.FindStackFrameEntryByAddress(0x3A00); 1346+ EXPECT_EQ((Module::StackFrameEntry*)NULL, s); 1347+} 1348