tools/profiler/LulExidx.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
     4 /* libunwind - a platform-independent unwind library
     5    Copyright 2011 Linaro Limited
     7 This file is part of libunwind.
     9 Permission is hereby granted, free of charge, to any person obtaining
    10 a copy of this software and associated documentation files (the
    11 "Software"), to deal in the Software without restriction, including
    12 without limitation the rights to use, copy, modify, merge, publish,
    13 distribute, sublicense, and/or sell copies of the Software, and to
    14 permit persons to whom the Software is furnished to do so, subject to
    15 the following conditions:
    17 The above copyright notice and this permission notice shall be
    18 included in all copies or substantial portions of the Software.
    20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    21 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    23 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
    24 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    25 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
    26 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
    29 // Copyright (c) 2010 Google Inc.
    30 // All rights reserved.
    31 //
    32 // Redistribution and use in source and binary forms, with or without
    33 // modification, are permitted provided that the following conditions are
    34 // met:
    35 //
    36 //     * Redistributions of source code must retain the above copyright
    37 // notice, this list of conditions and the following disclaimer.
    38 //     * Redistributions in binary form must reproduce the above
    39 // copyright notice, this list of conditions and the following disclaimer
    40 // in the documentation and/or other materials provided with the
    41 // distribution.
    42 //     * Neither the name of Google Inc. nor the names of its
    43 // contributors may be used to endorse or promote products derived from
    44 // this software without specific prior written permission.
    45 //
    46 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    47 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    48 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    49 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    50 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    51 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    52 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    53 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    54 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    55 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    56 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    59 // Derived from libunwind, with extensive modifications.
    61 // This file translates EXIDX unwind information into the same format
    62 // that LUL uses for CFI information.  Hence LUL's CFI unwinding
    63 // abilities also become usable for EXIDX.
    64 //
    65 // See: "Exception Handling ABI for the ARM Architecture", ARM IHI 0038A
    66 // http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038a/IHI0038A_ehabi.pdf
    68 // EXIDX data is presented in two parts:
    69 //
    70 // * an index table.  This contains two words per routine,
    71 //   the first of which identifies the routine, and the second
    72 //   of which is a reference to the unwind bytecode.  If the
    73 //   bytecode is very compact -- 3 bytes or less -- it can be
    74 //   stored directly in the second word.
    75 //
    76 // * an area containing the unwind bytecodes.
    77 //
    78 // General flow is: ExceptionTableInfo::Start iterates over all
    79 // of the index table entries (pairs).  For each entry, it:
    80 //
    81 // * calls ExceptionTableInfo::ExtabEntryExtract to copy the bytecode
    82 //   out into an intermediate buffer.
    84 // * uses ExceptionTableInfo::ExtabEntryDecode to parse the intermediate
    85 //   buffer.  Each bytecode instruction is bundled into a
    86 //   arm_ex_to_module::extab_data structure, and handed to ..
    87 //
    88 // * .. ARMExToModule::ImproveStackFrame, which in turn hands it to
    89 //   ARMExToModule::TranslateCmd, and that generates the pseudo-CFI
    90 //   records that Breakpad stores.
    92 // This file is derived from the following files in
    93 // toolkit/crashreporter/google-breakpad:
    94 //   src/common/arm_ex_to_module.cc
    95 //   src/common/arm_ex_reader.cc
    97 #include "mozilla/Assertions.h"
    98 #include "mozilla/NullPtr.h"
   100 #include "LulExidxExt.h"
   103 #define ARM_EXBUF_START(x) (((x) >> 4) & 0x0f)
   104 #define ARM_EXBUF_COUNT(x) ((x) & 0x0f)
   105 #define ARM_EXBUF_END(x)   (ARM_EXBUF_START(x) + ARM_EXBUF_COUNT(x))
   107 namespace lul {
   109 // Translate command from extab_data to command for Module.
   110 int ARMExToModule::TranslateCmd(const struct extab_data* edata,
   111                                 LExpr& vsp) {
   112   int ret = 0;
   113   switch (edata->cmd) {
   114     case ARM_EXIDX_CMD_FINISH:
   115       /* Copy LR to PC if there isn't currently a rule for PC in force. */
   116       if (curr_rules_.mR15expr.mHow == LExpr::UNKNOWN) {
   117         if (curr_rules_.mR14expr.mHow == LExpr::UNKNOWN) {
   118           curr_rules_.mR15expr = LExpr(LExpr::NODEREF, DW_REG_ARM_R14, 0);
   119         } else {
   120           curr_rules_.mR15expr = curr_rules_.mR14expr;
   121         }
   122       }
   123       break;
   124     case ARM_EXIDX_CMD_SUB_FROM_VSP:
   125       vsp = vsp.add_delta(- static_cast<long>(edata->data));
   126       break;
   127     case ARM_EXIDX_CMD_ADD_TO_VSP:
   128       vsp = vsp.add_delta(static_cast<long>(edata->data));
   129       break;
   130     case ARM_EXIDX_CMD_REG_POP:
   131       for (unsigned int i = 0; i < 16; i++) {
   132         if (edata->data & (1 << i)) {
   133           // See if we're summarising for int register |i|.  If so,
   134           // describe how to pull it off the stack.  The cast of |i| is
   135           // a bit of a kludge but works because DW_REG_ARM_Rn has the
   136           // value |n|, for 0 <= |n| <= 15 -- that is, for the ARM 
   137           // general-purpose registers.
   138           LExpr* regI_exprP = curr_rules_.ExprForRegno((DW_REG_NUMBER)i);
   139           if (regI_exprP) {
   140             *regI_exprP = vsp.deref();
   141           }
   142           vsp = vsp.add_delta(4);
   143         }
   144       }
   145       /* Set cfa in case the SP got popped. */
   146       if (edata->data & (1 << 13)) {
   147         vsp = curr_rules_.mR13expr;
   148       }
   149       break;
   150     case ARM_EXIDX_CMD_REG_TO_SP: {
   151       MOZ_ASSERT (edata->data < 16);
   152       int    reg_no    = edata->data;
   153       // Same comment as above, re the casting of |reg_no|, applies.
   154       LExpr* reg_exprP = curr_rules_.ExprForRegno((DW_REG_NUMBER)reg_no);
   155       if (reg_exprP) {
   156         if (reg_exprP->mHow == LExpr::UNKNOWN) {
   157           curr_rules_.mR13expr = LExpr(LExpr::NODEREF, reg_no, 0);
   158         } else {
   159           curr_rules_.mR13expr = *reg_exprP;
   160         }
   161         vsp = curr_rules_.mR13expr;
   162       }
   163       break;
   164     }
   165     case ARM_EXIDX_CMD_VFP_POP:
   166       /* Don't recover VFP registers, but be sure to adjust the stack
   167          pointer. */
   168       for (unsigned int i = ARM_EXBUF_START(edata->data);
   169            i <= ARM_EXBUF_END(edata->data); i++) {
   170         vsp = vsp.add_delta(8);
   171       }
   172       if (!(edata->data & ARM_EXIDX_VFP_FSTMD)) {
   173         vsp = vsp.add_delta(4);
   174       }
   175       break;
   176     case ARM_EXIDX_CMD_WREG_POP:
   177       for (unsigned int i = ARM_EXBUF_START(edata->data);
   178            i <= ARM_EXBUF_END(edata->data); i++) {
   179         vsp = vsp.add_delta(8);
   180       }
   181       break;
   182     case ARM_EXIDX_CMD_WCGR_POP:
   183       // Pop wCGR registers under mask {wCGR3,2,1,0}, hence "i < 4"
   184       for (unsigned int i = 0; i < 4; i++) {
   185         if (edata->data & (1 << i)) {
   186           vsp = vsp.add_delta(4);
   187         }
   188       }
   189       break;
   190     case ARM_EXIDX_CMD_REFUSED:
   191     case ARM_EXIDX_CMD_RESERVED:
   192       ret = -1;
   193       break;
   194   }
   195   return ret;
   196 }
   198 void ARMExToModule::AddStackFrame(uintptr_t addr, size_t size) {
   199   // Here we are effectively reinitialising the EXIDX summariser for a
   200   // new code address range.  smap_ stays unchanged.  All other fields
   201   // are reinitialised.
   202   vsp_ = LExpr(LExpr::NODEREF, DW_REG_ARM_R13, 0);
   203   (void) new (&curr_rules_) RuleSet();
   204   curr_rules_.mAddr = (uintptr_t)addr;
   205   curr_rules_.mLen  = (uintptr_t)size;
   206   if (0) {
   207     char buf[100];
   208     sprintf(buf, "  AddStackFrame    %llx .. %llx",
   209             (uint64_t)addr, (uint64_t)(addr + size - 1));
   210     log_(buf);
   211   }
   212 }
   214 int ARMExToModule::ImproveStackFrame(const struct extab_data* edata) {
   215   return TranslateCmd(edata, vsp_) ;
   216 }
   218 void ARMExToModule::DeleteStackFrame() {
   219 }
   221 void ARMExToModule::SubmitStackFrame() {
   222   // JRS: I'm really not sure what this means, or if it is necessary
   223   // return address always winds up in pc
   224   //stack_frame_entry_->initial_rules[ustr__ZDra()] // ".ra"
   225   //  = stack_frame_entry_->initial_rules[ustr__pc()];
   226   // maybe don't need to do anything here?
   228   // the final value of vsp is the new value of sp
   229   curr_rules_.mR13expr = vsp_;
   231   // Finally, add the completed RuleSet to the SecMap
   232   if (curr_rules_.mLen > 0) {
   234     // Futz with the rules for r4 .. r11 in the same way as happens
   235     // with the CFI summariser:
   236     /* Mark callee-saved registers (r4 .. r11) as unchanged, if there is
   237        no other information about them.  FIXME: do this just once, at
   238        the point where the ruleset is committed. */
   239     if (curr_rules_.mR7expr.mHow == LExpr::UNKNOWN) {
   240       curr_rules_.mR7expr = LExpr(LExpr::NODEREF, DW_REG_ARM_R7, 0);
   241     }
   242     if (curr_rules_.mR11expr.mHow == LExpr::UNKNOWN) {
   243       curr_rules_.mR11expr = LExpr(LExpr::NODEREF, DW_REG_ARM_R11, 0);
   244     }
   245     if (curr_rules_.mR12expr.mHow == LExpr::UNKNOWN) {
   246       curr_rules_.mR12expr = LExpr(LExpr::NODEREF, DW_REG_ARM_R12, 0);
   247     }
   248     if (curr_rules_.mR14expr.mHow == LExpr::UNKNOWN) {
   249       curr_rules_.mR14expr = LExpr(LExpr::NODEREF, DW_REG_ARM_R14, 0);
   250     }
   252     // And add them
   253     smap_->AddRuleSet(&curr_rules_);
   255     if (0) {
   256       curr_rules_.Print(log_);
   257     }
   258     if (0) {
   259       char buf[100];
   260       sprintf(buf, "  SubmitStackFrame %llx .. %llx",
   261               (uint64_t)curr_rules_.mAddr,
   262               (uint64_t)(curr_rules_.mAddr + curr_rules_.mLen - 1));
   263       log_(buf);
   264     }
   265   }
   266 }
   269 #define ARM_EXIDX_CANT_UNWIND 0x00000001
   270 #define ARM_EXIDX_COMPACT     0x80000000
   271 #define ARM_EXTBL_OP_FINISH   0xb0
   272 #define ARM_EXIDX_TABLE_LIMIT (255*4)
   274 using lul::ARM_EXIDX_CMD_FINISH;
   275 using lul::ARM_EXIDX_CMD_SUB_FROM_VSP;
   276 using lul::ARM_EXIDX_CMD_ADD_TO_VSP;
   277 using lul::ARM_EXIDX_CMD_REG_POP;
   278 using lul::ARM_EXIDX_CMD_REG_TO_SP;
   279 using lul::ARM_EXIDX_CMD_VFP_POP;
   280 using lul::ARM_EXIDX_CMD_WREG_POP;
   281 using lul::ARM_EXIDX_CMD_WCGR_POP;
   282 using lul::ARM_EXIDX_CMD_RESERVED;
   283 using lul::ARM_EXIDX_CMD_REFUSED;
   284 using lul::exidx_entry;
   285 using lul::ARM_EXIDX_VFP_SHIFT_16;
   286 using lul::ARM_EXIDX_VFP_FSTMD;
   287 using lul::MemoryRange;
   290 static void* Prel31ToAddr(const void* addr)
   291 {
   292   uint32_t offset32 = *reinterpret_cast<const uint32_t*>(addr);
   293   // sign extend offset32[30:0] to 64 bits -- copy bit 30 to positions
   294   // 63:31 inclusive.
   295   uint64_t offset64 = offset32;
   296   if (offset64 & (1ULL << 30))
   297     offset64 |= 0xFFFFFFFF80000000ULL;
   298   else
   299     offset64 &= 0x000000007FFFFFFFULL;
   300   return ((char*)addr) + (uintptr_t)offset64;
   301 }
   304 // Extract unwind bytecode for the function denoted by |entry| into |buf|,
   305 // and return the number of bytes of |buf| written, along with a code
   306 // indicating the outcome.
   308 ExceptionTableInfo::ExExtractResult
   309 ExceptionTableInfo::ExtabEntryExtract(const struct exidx_entry* entry,
   310                                       uint8_t* buf, size_t buf_size,
   311                                       /*OUT*/size_t* buf_used)
   312 {
   313   MemoryRange mr_out(buf, buf_size);
   315   *buf_used = 0;
   317 # define PUT_BUF_U8(_byte) \
   318   do { if (!mr_out.Covers(*buf_used, 1)) return ExOutBufOverflow; \
   319        buf[(*buf_used)++] = (_byte); } while (0)
   321 # define GET_EX_U32(_lval, _addr, _sec_mr) \
   322   do { if (!(_sec_mr).Covers(reinterpret_cast<const uint8_t*>(_addr) \
   323                              - (_sec_mr).data(), 4)) \
   324          return ExInBufOverflow; \
   325        (_lval) = *(reinterpret_cast<const uint32_t*>(_addr)); } while (0)
   327 # define GET_EXIDX_U32(_lval, _addr) \
   328             GET_EX_U32(_lval, _addr, mr_exidx_)
   329 # define GET_EXTAB_U32(_lval, _addr) \
   330             GET_EX_U32(_lval, _addr, mr_extab_)
   332   uint32_t data;
   333   GET_EXIDX_U32(data, &entry->data);
   335   // A function can be marked CANT_UNWIND if (eg) it is known to be
   336   // at the bottom of the stack.
   337   if (data == ARM_EXIDX_CANT_UNWIND)
   338     return ExCantUnwind;
   340   uint32_t  pers;          // personality number
   341   uint32_t  extra;         // number of extra data words required
   342   uint32_t  extra_allowed; // number of extra data words allowed
   343   uint32_t* extbl_data;    // the handler entry, if not inlined
   345   if (data & ARM_EXIDX_COMPACT) {
   346     // The handler table entry has been inlined into the index table entry.
   347     // In this case it can only be an ARM-defined compact model, since
   348     // bit 31 is 1.  Only personalities 0, 1 and 2 are defined for the
   349     // ARM compact model, but 1 and 2 are "Long format" and may require
   350     // extra data words.  Hence the allowable personalities here are:
   351     //   personality 0, in which case 'extra' has no meaning
   352     //   personality 1, with zero extra words
   353     //   personality 2, with zero extra words
   354     extbl_data = nullptr;
   355     pers  = (data >> 24) & 0x0F;
   356     extra = (data >> 16) & 0xFF;
   357     extra_allowed = 0;
   358   }
   359   else {
   360     // The index table entry is a pointer to the handler entry.  Note
   361     // that Prel31ToAddr will read the given address, but we already
   362     // range-checked above.
   363     extbl_data = reinterpret_cast<uint32_t*>(Prel31ToAddr(&entry->data));
   364     GET_EXTAB_U32(data, extbl_data);
   365     if (!(data & ARM_EXIDX_COMPACT)) {
   366       // This denotes a "generic model" handler.  That will involve
   367       // executing arbitary machine code, which is something we
   368       // can't represent here; hence reject it.
   369       return ExCantRepresent;
   370     }
   371     // So we have a compact model representation.  Again, 3 possible
   372     // personalities, but this time up to 255 allowable extra words.
   373     pers  = (data >> 24) & 0x0F;
   374     extra = (data >> 16) & 0xFF;
   375     extra_allowed = 255;
   376     extbl_data++;
   377   }
   379   // Now look at the the handler table entry.  The first word is
   380   // |data| and subsequent words start at |*extbl_data|.  The number
   381   // of extra words to use is |extra|, provided that the personality
   382   // allows extra words.  Even if it does, none may be available --
   383   // extra_allowed is the maximum number of extra words allowed. */
   384   if (pers == 0) {
   385     // "Su16" in the documentation -- 3 unwinding insn bytes
   386     // |extra| has no meaning here; instead that byte is an unwind-info byte
   387     PUT_BUF_U8(data >> 16);
   388     PUT_BUF_U8(data >> 8);
   389     PUT_BUF_U8(data);
   390   }
   391   else if ((pers == 1 || pers == 2) && extra <= extra_allowed) {
   392     // "Lu16" or "Lu32" respectively -- 2 unwinding insn bytes,
   393     // and up to 255 extra words.
   394     PUT_BUF_U8(data >> 8);
   395     PUT_BUF_U8(data);
   396     for (uint32_t j = 0; j < extra; j++) {
   397       GET_EXTAB_U32(data, extbl_data);
   398       extbl_data++;
   399       PUT_BUF_U8(data >> 24);
   400       PUT_BUF_U8(data >> 16);
   401       PUT_BUF_U8(data >> 8);
   402       PUT_BUF_U8(data >> 0);
   403     }
   404   }
   405   else {
   406     // The entry is invalid.
   407     return ExInvalid;
   408   }
   410   // Make sure the entry is terminated with "FINISH"
   411   if (*buf_used > 0 && buf[(*buf_used) - 1] != ARM_EXTBL_OP_FINISH)
   412     PUT_BUF_U8(ARM_EXTBL_OP_FINISH);
   414   return ExSuccess;
   416 # undef GET_EXTAB_U32
   417 # undef GET_EXIDX_U32
   418 # undef GET_U32
   419 # undef PUT_BUF_U8
   420 }
   423 // Take the unwind information extracted by ExtabEntryExtract
   424 // and parse it into frame-unwind instructions.  These are as
   425 // specified in "Table 4, ARM-defined frame-unwinding instructions"
   426 // in the specification document detailed in comments at the top
   427 // of this file.
   428 //
   429 // This reads from |buf[0, +data_size)|.  It checks for overruns of
   430 // the input buffer and returns a negative value if that happens, or
   431 // for any other failure cases.  It returns zero in case of success.
   432 int ExceptionTableInfo::ExtabEntryDecode(const uint8_t* buf, size_t buf_size)
   433 {
   434   if (buf == nullptr || buf_size == 0)
   435     return -1;
   437   MemoryRange mr_in(buf, buf_size);
   438   const uint8_t* buf_initially = buf;
   440 # define GET_BUF_U8(_lval) \
   441   do { if (!mr_in.Covers(buf - buf_initially, 1)) return -1; \
   442        (_lval) = *(buf++); } while (0)
   444   const uint8_t* end = buf + buf_size;
   446   while (buf < end) {
   447     struct lul::extab_data edata;
   448     memset(&edata, 0, sizeof(edata));
   450     uint8_t op;
   451     GET_BUF_U8(op);
   452     if ((op & 0xc0) == 0x00) {
   453       // vsp = vsp + (xxxxxx << 2) + 4
   454       edata.cmd = ARM_EXIDX_CMD_ADD_TO_VSP;
   455       edata.data = (((int)op & 0x3f) << 2) + 4;
   456     }
   457     else if ((op & 0xc0) == 0x40) {
   458       // vsp = vsp - (xxxxxx << 2) - 4
   459       edata.cmd = ARM_EXIDX_CMD_SUB_FROM_VSP;
   460       edata.data = (((int)op & 0x3f) << 2) + 4;
   461     }
   462     else if ((op & 0xf0) == 0x80) {
   463       uint8_t op2;
   464       GET_BUF_U8(op2);
   465       if (op == 0x80 && op2 == 0x00) {
   466         // Refuse to unwind
   467         edata.cmd = ARM_EXIDX_CMD_REFUSED;
   468       } else {
   469         // Pop up to 12 integer registers under masks {r15-r12},{r11-r4}
   470         edata.cmd = ARM_EXIDX_CMD_REG_POP;
   471         edata.data = ((op & 0xf) << 8) | op2;
   472         edata.data = edata.data << 4;
   473       }
   474     }
   475     else if ((op & 0xf0) == 0x90) {
   476       if (op == 0x9d || op == 0x9f) {
   477         // 9d: Reserved as prefix for ARM register to register moves
   478         // 9f: Reserved as perfix for Intel Wireless MMX reg to reg moves
   479         edata.cmd = ARM_EXIDX_CMD_RESERVED;
   480       } else {
   481         // Set vsp = r[nnnn]
   482         edata.cmd = ARM_EXIDX_CMD_REG_TO_SP;
   483         edata.data = op & 0x0f;
   484       }
   485     }
   486     else if ((op & 0xf0) == 0xa0) {
   487       // Pop r4 to r[4+nnn],          or
   488       // Pop r4 to r[4+nnn] and r14   or
   489       unsigned end = (op & 0x07);
   490       edata.data = (1 << (end + 1)) - 1;
   491       edata.data = edata.data << 4;
   492       if (op & 0x08) edata.data |= 1 << 14;
   493       edata.cmd = ARM_EXIDX_CMD_REG_POP;
   494     }
   495     else if (op == ARM_EXTBL_OP_FINISH) {
   496       // Finish
   497       edata.cmd = ARM_EXIDX_CMD_FINISH;
   498       buf = end;
   499     }
   500     else if (op == 0xb1) {
   501       uint8_t op2;
   502       GET_BUF_U8(op2);
   503       if (op2 == 0 || (op2 & 0xf0)) {
   504         // Spare
   505         edata.cmd = ARM_EXIDX_CMD_RESERVED;
   506       } else {
   507         // Pop integer registers under mask {r3,r2,r1,r0}
   508         edata.cmd = ARM_EXIDX_CMD_REG_POP;
   509         edata.data = op2 & 0x0f;
   510       }
   511     }
   512     else if (op == 0xb2) {
   513       // vsp = vsp + 0x204 + (uleb128 << 2)
   514       uint64_t offset = 0;
   515       uint8_t byte, shift = 0;
   516       do {
   517         GET_BUF_U8(byte);
   518         offset |= (byte & 0x7f) << shift;
   519         shift += 7;
   520       } while ((byte & 0x80) && buf < end);
   521       edata.data = offset * 4 + 0x204;
   522       edata.cmd = ARM_EXIDX_CMD_ADD_TO_VSP;
   523     }
   524     else if (op == 0xb3 || op == 0xc8 || op == 0xc9) {
   525       // b3: Pop VFP regs D[ssss]    to D[ssss+cccc],    FSTMFDX-ishly
   526       // c8: Pop VFP regs D[16+ssss] to D[16+ssss+cccc], FSTMFDD-ishly
   527       // c9: Pop VFP regs D[ssss]    to D[ssss+cccc],    FSTMFDD-ishly
   528       edata.cmd = ARM_EXIDX_CMD_VFP_POP;
   529       GET_BUF_U8(edata.data);
   530       if (op == 0xc8) edata.data |= ARM_EXIDX_VFP_SHIFT_16;
   531       if (op != 0xb3) edata.data |= ARM_EXIDX_VFP_FSTMD;
   532     }
   533     else if ((op & 0xf8) == 0xb8 || (op & 0xf8) == 0xd0) {
   534       // b8: Pop VFP regs D[8] to D[8+nnn], FSTMFDX-ishly
   535       // d0: Pop VFP regs D[8] to D[8+nnn], FSTMFDD-ishly
   536       edata.cmd = ARM_EXIDX_CMD_VFP_POP;
   537       edata.data = 0x80 | (op & 0x07);
   538       if ((op & 0xf8) == 0xd0) edata.data |= ARM_EXIDX_VFP_FSTMD;
   539     }
   540     else if (op >= 0xc0 && op <= 0xc5) {
   541       // Intel Wireless MMX pop wR[10]-wr[10+nnn], nnn != 6,7
   542       edata.cmd = ARM_EXIDX_CMD_WREG_POP;
   543       edata.data = 0xa0 | (op & 0x07);
   544     }
   545     else if (op == 0xc6) {
   546       // Intel Wireless MMX pop wR[ssss] to wR[ssss+cccc]
   547       edata.cmd = ARM_EXIDX_CMD_WREG_POP;
   548       GET_BUF_U8(edata.data);
   549     }
   550     else if (op == 0xc7) {
   551       uint8_t op2;
   552       GET_BUF_U8(op2);
   553       if (op2 == 0 || (op2 & 0xf0)) {
   554         // Spare
   555         edata.cmd = ARM_EXIDX_CMD_RESERVED;
   556       } else {
   557         // Intel Wireless MMX pop wCGR registers under mask {wCGR3,2,1,0}
   558         edata.cmd = ARM_EXIDX_CMD_WCGR_POP;
   559         edata.data = op2 & 0x0f;
   560       }
   561     }
   562     else {
   563       // Spare
   564       edata.cmd = ARM_EXIDX_CMD_RESERVED;
   565     }
   567     int ret = handler_->ImproveStackFrame(&edata);
   568     if (ret < 0) return ret;
   569   }
   570   return 0;
   572 # undef GET_BUF_U8
   573 }
   575 void ExceptionTableInfo::Start()
   576 {
   577   const struct exidx_entry* start
   578     = reinterpret_cast<const struct exidx_entry*>(mr_exidx_.data());
   579   const struct exidx_entry* end
   580     = reinterpret_cast<const struct exidx_entry*>(mr_exidx_.data()
   581                                                   + mr_exidx_.length());
   583   // Iterate over each of the EXIDX entries (pairs of 32-bit words).
   584   // These occupy the entire .exidx section.
   585   for (const struct exidx_entry* entry = start; entry < end; ++entry) {
   587     // Figure out the code address range that this table entry is
   588     // associated with.
   589     //
   590     // I don't claim to understand the biasing here.  It appears that
   591     //   (Prel31ToAddr(&entry->addr))
   592     //    - mapping_addr_ + loading_addr_) & 0x7fffffff
   593     // produces a SVMA.  Adding the text_bias_ gives plausible AVMAs.
   594     uint32_t svma = (reinterpret_cast<char*>(Prel31ToAddr(&entry->addr))
   595                      - mapping_addr_ + loading_addr_) & 0x7fffffff;
   596     uint32_t next_svma;
   597     if (entry < end - 1) {
   598       next_svma = (reinterpret_cast<char*>(Prel31ToAddr(&((entry + 1)->addr)))
   599                    - mapping_addr_ + loading_addr_) & 0x7fffffff;
   600     } else {
   601       // This is the last EXIDX entry in the sequence, so we don't
   602       // have an address for the start of the next function, to limit
   603       // this one.  Instead use the address of the last byte of the
   604       // text section associated with this .exidx section, that we
   605       // have been given.  So as to avoid junking up the CFI unwind
   606       // tables with absurdly large address ranges in the case where
   607       // text_last_svma_ is wrong, only use the value if it is nonzero
   608       // and within one page of |svma|.  Otherwise assume a length of 1.
   609       //
   610       // In some cases, gcc has been observed to finish the exidx
   611       // section with an entry of length 1 marked CANT_UNWIND,
   612       // presumably exactly for the purpose of giving a definite
   613       // length for the last real entry, without having to look at
   614       // text segment boundaries.
   615       bool plausible = false;
   616       next_svma = svma + 1;
   617       if (text_last_svma_ != 0) {
   618         uint32_t maybe_next_svma = text_last_svma_ + 1;
   619         if (maybe_next_svma > svma && maybe_next_svma - svma <= 4096) {
   620           next_svma = maybe_next_svma;
   621           plausible = true;
   622         }
   623       }
   624       if (!plausible) {
   625         char buf[100];
   626         snprintf(buf, sizeof(buf),
   627                  "ExceptionTableInfo: implausible EXIDX last entry size %d"
   628                  "; using 1 instead.", (int32_t)(text_last_svma_ - svma));
   629         buf[sizeof(buf)-1] = 0;
   630         log_(buf);
   631       }
   632     }
   634     // Extract the unwind info into |buf|.  This might fail for
   635     // various reasons.  It involves reading both the .exidx and
   636     // .extab sections.  All accesses to those sections are
   637     // bounds-checked.
   638     uint8_t buf[ARM_EXIDX_TABLE_LIMIT];
   639     size_t buf_used = 0;
   640     ExExtractResult res = ExtabEntryExtract(entry, buf, sizeof(buf), &buf_used);
   641     if (res != ExSuccess) {
   642       // Couldn't extract the unwind info, for some reason.  Move on.
   643       switch (res) {
   644         case ExInBufOverflow:
   645           log_("ExtabEntryExtract: .exidx/.extab section overrun");
   646           break;
   647         case ExOutBufOverflow:
   648           log_("ExtabEntryExtract: bytecode buffer overflow");
   649           break;
   650         case ExCantUnwind:
   651           log_("ExtabEntryExtract: function is marked CANT_UNWIND");
   652           break;
   653         case ExCantRepresent:
   654           log_("ExtabEntryExtract: bytecode can't be represented");
   655           break;
   656         case ExInvalid:
   657           log_("ExtabEntryExtract: index table entry is invalid");
   658           break;
   659         default: {
   660           char buf[100];
   661           snprintf(buf, sizeof(buf),
   662                    "ExtabEntryExtract: unknown error: %d", (int)res);
   663           buf[sizeof(buf)-1] = 0;
   664           log_(buf);
   665           break;
   666         }
   667       }
   668       continue;
   669     }
   671     // Finally, work through the unwind instructions in |buf| and
   672     // create CFI entries that Breakpad can use.  This can also fail.
   673     // First, add a new stack frame entry, into which ExtabEntryDecode
   674     // will write the CFI entries.
   675     handler_->AddStackFrame(svma + text_bias_, next_svma - svma);
   676     int ret = ExtabEntryDecode(buf, buf_used);
   677     if (ret < 0) {
   678       handler_->DeleteStackFrame();
   679       char buf[100];
   680       snprintf(buf, sizeof(buf),
   681                "ExtabEntryDecode: failed with error code: %d", ret);
   682       buf[sizeof(buf)-1] = 0;
   683       log_(buf);
   684       continue;
   685     }
   686     handler_->SubmitStackFrame();
   687   } /* iterating over .exidx */
   688 }
   690 } // namespace lul

mercurial