Home | History | Annotate | Download | only in m_debuginfo
      1 /* -*- mode: C; c-basic-offset: 3; -*- */
      2 
      3 /*--------------------------------------------------------------------*/
      4 /*--- Reading of ARM(32) EXIDX unwind information      readexidx.c ---*/
      5 /*--------------------------------------------------------------------*/
      6 
      7 /*
      8    This file is part of Valgrind, a dynamic binary instrumentation
      9    framework.
     10 
     11    Copyright (C) 2014-2014 Mozilla Foundation
     12 
     13    This program is free software; you can redistribute it and/or
     14    modify it under the terms of the GNU General Public License as
     15    published by the Free Software Foundation; either version 2 of the
     16    License, or (at your option) any later version.
     17 
     18    This program is distributed in the hope that it will be useful, but
     19    WITHOUT ANY WARRANTY; without even the implied warranty of
     20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     21    General Public License for more details.
     22 
     23    You should have received a copy of the GNU General Public License
     24    along with this program; if not, write to the Free Software
     25    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
     26    02111-1307, USA.
     27 
     28    The GNU General Public License is contained in the file COPYING.
     29 */
     30 
     31 /* libunwind - a platform-independent unwind library
     32    Copyright 2011 Linaro Limited
     33 
     34 This file is part of libunwind.
     35 
     36 Permission is hereby granted, free of charge, to any person obtaining
     37 a copy of this software and associated documentation files (the
     38 "Software"), to deal in the Software without restriction, including
     39 without limitation the rights to use, copy, modify, merge, publish,
     40 distribute, sublicense, and/or sell copies of the Software, and to
     41 permit persons to whom the Software is furnished to do so, subject to
     42 the following conditions:
     43 
     44 The above copyright notice and this permission notice shall be
     45 included in all copies or substantial portions of the Software.
     46 
     47 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     48 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     49 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     50 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
     51 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
     52 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     53 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
     54 
     55 
     56 // Copyright (c) 2010 Google Inc.
     57 // All rights reserved.
     58 //
     59 // Redistribution and use in source and binary forms, with or without
     60 // modification, are permitted provided that the following conditions are
     61 // met:
     62 //
     63 //     * Redistributions of source code must retain the above copyright
     64 // notice, this list of conditions and the following disclaimer.
     65 //     * Redistributions in binary form must reproduce the above
     66 // copyright notice, this list of conditions and the following disclaimer
     67 // in the documentation and/or other materials provided with the
     68 // distribution.
     69 //     * Neither the name of Google Inc. nor the names of its
     70 // contributors may be used to endorse or promote products derived from
     71 // this software without specific prior written permission.
     72 //
     73 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     74 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     75 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     76 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     77 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     78 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     79 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     80 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     81 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     82 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     83 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     84 
     85 
     86 // Derived originally from libunwind, with very extensive modifications.
     87 /* Contributed by Julian Seward <jseward (at) acm.org> */
     88 
     89 
     90 // This file translates EXIDX unwind information into the same format
     91 // that Valgrind uses for CFI information.  Hence Valgrind's CFI
     92 // unwinding abilities also become usable for EXIDX.
     93 //
     94 // See: "Exception Handling ABI for the ARM Architecture", ARM IHI 0038A
     95 // http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038a/IHI0038A_ehabi.pdf
     96 
     97 // EXIDX data is presented in two parts:
     98 //
     99 // * an index table.  This contains two words per routine,
    100 //   the first of which identifies the routine, and the second
    101 //   of which is a reference to the unwind bytecode.  If the
    102 //   bytecode is very compact -- 3 bytes or less -- it can be
    103 //   stored directly in the second word.
    104 //
    105 // * an area containing the unwind bytecodes.
    106 //
    107 // General flow is: ML_(read_exidx) iterates over all
    108 // of the index table entries (pairs).  For each entry, it:
    109 //
    110 // * calls ExtabEntryExtract to copy the bytecode out into
    111 // an intermediate buffer.
    112 
    113 // * uses ExtabEntryDecode to parse the intermediate
    114 //   buffer.  Each bytecode instruction is bundled into a
    115 //   arm_ex_to_module::extab_data structure, and handed to ..
    116 //
    117 // * .. TranslateCmd, which generates the pseudo-CFI
    118 //   records that Valgrind stores.
    119 
    120 // This file is derived from the following files in the Mozilla tree
    121 // toolkit/crashreporter/google-breakpad:
    122 //   src/common/arm_ex_to_module.cc
    123 //   src/common/arm_ex_reader.cc
    124 
    125 
    126 #if defined(VGA_arm)
    127 
    128 #include "pub_core_basics.h"
    129 #include "pub_core_libcbase.h"
    130 #include "pub_core_libcprint.h"
    131 #include "pub_core_libcassert.h"
    132 #include "pub_core_options.h"
    133 
    134 #include "priv_storage.h"
    135 #include "priv_readexidx.h"
    136 
    137 
    138 static void complain ( const HChar* str )
    139 {
    140    if (!VG_(clo_xml) && VG_(clo_verbosity) > 1)
    141       VG_(message)(Vg_UserMsg,
    142                    "  Warning: whilst reading EXIDX: %s\n", str);
    143 }
    144 
    145 
    146 /*------------------------------------------------------------*/
    147 /*--- MemoryRange                                          ---*/
    148 /*------------------------------------------------------------*/
    149 
    150 typedef  struct { Addr start; SizeT len; }  MemoryRange;
    151 
    152 /* Initialise |mr| for [start .. start+len).  Zero ranges are allowed,
    153    but wraparounds are not.  Returns True on success. */
    154 static Bool MemoryRange__init ( /*OUT*/MemoryRange* mr,
    155                                 const void* startV, SizeT len )
    156 {
    157    VG_(memset)(mr, 0, sizeof(*mr));
    158    /* This relies on Addr being unsigned. */
    159    Addr start = (Addr)startV;
    160    if (len > 0 && start + len - 1 < start) {
    161       return False;
    162    }
    163    mr->start = start;
    164    mr->len   = len;
    165    return True;
    166 }
    167 
    168 static Bool MemoryRange__covers ( MemoryRange* mr,
    169                                   const void* startV, SizeT len )
    170 {
    171    vg_assert(len > 0);
    172    if (mr->len == 0) {
    173       return False;
    174    }
    175    Addr start = (Addr)startV;
    176    return start >= mr->start && start + len - 1 <= mr->start + mr->len - 1;
    177 }
    178 
    179 
    180 /*------------------------------------------------------------*/
    181 /*--- (Pass 1 of 3) The EXIDX extractor                    ---*/
    182 /*------------------------------------------------------------*/
    183 
    184 #define ARM_EXIDX_CANT_UNWIND 0x00000001
    185 #define ARM_EXIDX_COMPACT     0x80000000
    186 #define ARM_EXTBL_OP_FINISH   0xb0
    187 #define ARM_EXIDX_TABLE_LIMIT (255*4)
    188 
    189 /* These are in the ARM-defined format, so their layout is important. */
    190 typedef
    191    struct { UInt addr; UInt data; }
    192    ExidxEntry;
    193 
    194 
    195 typedef
    196    enum {
    197       ExSuccess=1,      // success
    198       ExInBufOverflow,  // out-of-range while reading .exidx
    199       ExOutBufOverflow, // output buffer is too small
    200       ExCantUnwind,     // this function is marked CANT_UNWIND
    201       ExCantRepresent,  // entry valid, but we can't represent it
    202       ExInvalid         // entry is invalid
    203    }
    204    ExExtractResult;
    205 
    206 
    207 /* Helper function for fishing bits out of the EXIDX representation. */
    208 static void* Prel31ToAddr(const void* addr)
    209 {
    210    UInt offset32 = *(const UInt*)addr;
    211    // sign extend offset32[30:0] to 64 bits -- copy bit 30 to positions
    212    // 63:31 inclusive.
    213    ULong offset64 = offset32;
    214    if (offset64 & (1ULL << 30))
    215       offset64 |= 0xFFFFFFFF80000000ULL;
    216    else
    217       offset64 &= 0x000000007FFFFFFFULL;
    218    return ((UChar*)addr) + (UWord)offset64;
    219 }
    220 
    221 
    222 // Extract unwind bytecode for the function denoted by |entry| into |buf|,
    223 // and return the number of bytes of |buf| written, along with a code
    224 // indicating the outcome.
    225 static
    226 ExExtractResult ExtabEntryExtract ( MemoryRange* mr_exidx,
    227                                     MemoryRange* mr_extab,
    228                                     const ExidxEntry* entry,
    229                                     UChar* buf, SizeT buf_size,
    230                                     /*OUT*/SizeT* buf_used)
    231 {
    232    Bool ok;
    233    MemoryRange mr_out;
    234    ok = MemoryRange__init(&mr_out, buf, buf_size);
    235    if (!ok) return ExOutBufOverflow;
    236 
    237    *buf_used = 0;
    238 
    239 #  define PUT_BUF_U8(_byte) \
    240       do { if (!MemoryRange__covers(&mr_out, &buf[*buf_used], 1)) \
    241               return ExOutBufOverflow; \
    242            buf[(*buf_used)++] = (_byte); } while (0)
    243 
    244 #  define GET_EX_U32(_lval, _addr, _mr) \
    245       do { if (!MemoryRange__covers((_mr), (void*)(_addr), 4)) \
    246               return ExInBufOverflow; \
    247            (_lval) = *(UInt*)(_addr); } while (0)
    248 
    249 #  define GET_EXIDX_U32(_lval, _addr) \
    250       GET_EX_U32(_lval, _addr, mr_exidx)
    251 
    252 #  define GET_EXTAB_U32(_lval, _addr) \
    253       GET_EX_U32(_lval, _addr, mr_extab)
    254 
    255    UInt data;
    256    GET_EXIDX_U32(data, &entry->data);
    257 
    258    // A function can be marked CANT_UNWIND if (eg) it is known to be
    259    // at the bottom of the stack.
    260    if (data == ARM_EXIDX_CANT_UNWIND)
    261       return ExCantUnwind;
    262 
    263    UInt  pers;          // personality number
    264    UInt  extra;         // number of extra data words required
    265    UInt  extra_allowed; // number of extra data words allowed
    266    UInt* extbl_data;    // the handler entry, if not inlined
    267 
    268    if (data & ARM_EXIDX_COMPACT) {
    269       // The handler table entry has been inlined into the index table entry.
    270       // In this case it can only be an ARM-defined compact model, since
    271       // bit 31 is 1.  Only personalities 0, 1 and 2 are defined for the
    272       // ARM compact model, but 1 and 2 are "Long format" and may require
    273       // extra data words.  Hence the allowable personalities here are:
    274       //   personality 0, in which case 'extra' has no meaning
    275       //   personality 1, with zero extra words
    276       //   personality 2, with zero extra words
    277       extbl_data = NULL;
    278       pers  = (data >> 24) & 0x0F;
    279       extra = (data >> 16) & 0xFF;
    280       extra_allowed = 0;
    281    }
    282    else {
    283       // The index table entry is a pointer to the handler entry.  Note
    284       // that Prel31ToAddr will read the given address, but we already
    285       // range-checked above.
    286       extbl_data = (UInt*)(Prel31ToAddr(&entry->data));
    287       GET_EXTAB_U32(data, extbl_data);
    288       if (!(data & ARM_EXIDX_COMPACT)) {
    289          // This denotes a "generic model" handler.  That will involve
    290          // executing arbitary machine code, which is something we
    291          // can't represent here; hence reject it.
    292          return ExCantRepresent;
    293       }
    294       // So we have a compact model representation.  Again, 3 possible
    295       // personalities, but this time up to 255 allowable extra words.
    296       pers  = (data >> 24) & 0x0F;
    297       extra = (data >> 16) & 0xFF;
    298       extra_allowed = 255;
    299       extbl_data++;
    300    }
    301 
    302    // Now look at the the handler table entry.  The first word is
    303    // |data| and subsequent words start at |*extbl_data|.  The number
    304    // of extra words to use is |extra|, provided that the personality
    305    // allows extra words.  Even if it does, none may be available --
    306    // extra_allowed is the maximum number of extra words allowed. */
    307    if (pers == 0) {
    308       // "Su16" in the documentation -- 3 unwinding insn bytes
    309       // |extra| has no meaning here; instead that byte is an unwind-info byte
    310       PUT_BUF_U8(data >> 16);
    311       PUT_BUF_U8(data >> 8);
    312       PUT_BUF_U8(data);
    313    }
    314    else if ((pers == 1 || pers == 2) && extra <= extra_allowed) {
    315       // "Lu16" or "Lu32" respectively -- 2 unwinding insn bytes,
    316       // and up to 255 extra words.
    317       PUT_BUF_U8(data >> 8);
    318       PUT_BUF_U8(data);
    319       UInt j;
    320       for (j = 0; j < extra; j++) {
    321          GET_EXTAB_U32(data, extbl_data);
    322          extbl_data++;
    323          PUT_BUF_U8(data >> 24);
    324          PUT_BUF_U8(data >> 16);
    325          PUT_BUF_U8(data >> 8);
    326          PUT_BUF_U8(data >> 0);
    327       }
    328    }
    329    else {
    330       // The entry is invalid.
    331       return ExInvalid;
    332    }
    333 
    334    // Make sure the entry is terminated with "FINISH"
    335    if (*buf_used > 0 && buf[(*buf_used) - 1] != ARM_EXTBL_OP_FINISH)
    336       PUT_BUF_U8(ARM_EXTBL_OP_FINISH);
    337 
    338    return ExSuccess;
    339 
    340 #  undef GET_EXTAB_U32
    341 #  undef GET_EXIDX_U32
    342 #  undef GET_U32
    343 #  undef PUT_BUF_U8
    344 }
    345 
    346 
    347 /*------------------------------------------------------------*/
    348 /*--- (Pass 2 of 3) The EXIDX decoder                      ---*/
    349 /*------------------------------------------------------------*/
    350 
    351 /* This (ExtabData) is an intermediate structure, used to carry
    352    information from the decoder (pass 2) to the summariser (pass 3).
    353    I don't think its layout is important. */
    354 typedef
    355    enum {
    356       ARM_EXIDX_CMD_FINISH=0x100,
    357       ARM_EXIDX_CMD_SUB_FROM_VSP,
    358       ARM_EXIDX_CMD_ADD_TO_VSP,
    359       ARM_EXIDX_CMD_REG_POP,
    360       ARM_EXIDX_CMD_REG_TO_SP,
    361       ARM_EXIDX_CMD_VFP_POP,
    362       ARM_EXIDX_CMD_WREG_POP,
    363       ARM_EXIDX_CMD_WCGR_POP,
    364       ARM_EXIDX_CMD_RESERVED,
    365       ARM_EXIDX_CMD_REFUSED
    366    }
    367    ExtabCmd;
    368 
    369 static const HChar* showExtabCmd ( ExtabCmd cmd ) {
    370    switch (cmd) {
    371       case ARM_EXIDX_CMD_FINISH:       return "FINISH";
    372       case ARM_EXIDX_CMD_SUB_FROM_VSP: return "SUB_FROM_VSP";
    373       case ARM_EXIDX_CMD_ADD_TO_VSP:   return "ADD_TO_VSP";
    374       case ARM_EXIDX_CMD_REG_POP:      return "REG_POP";
    375       case ARM_EXIDX_CMD_REG_TO_SP:    return "REG_TO_SP";
    376       case ARM_EXIDX_CMD_VFP_POP:      return "VFP_POP";
    377       case ARM_EXIDX_CMD_WREG_POP:     return "WREG_POP";
    378       case ARM_EXIDX_CMD_WCGR_POP:     return "WCGR_POP";
    379       case ARM_EXIDX_CMD_RESERVED:     return "RESERVED";
    380       case ARM_EXIDX_CMD_REFUSED:      return "REFUSED";
    381       default:                         return "???";
    382    }
    383 }
    384 
    385 
    386 typedef
    387    struct { ExtabCmd cmd; UInt data; }
    388    ExtabData;
    389 
    390 static void ppExtabData ( const ExtabData* etd ) {
    391    VG_(printf)("ExtabData{%-12s 0x%08x}", showExtabCmd(etd->cmd), etd->data);
    392 }
    393 
    394 
    395 enum extab_cmd_flags {
    396    ARM_EXIDX_VFP_SHIFT_16 = 1 << 16,
    397    ARM_EXIDX_VFP_FSTMD = 1 << 17, // distinguishes FSTMxxD from FSTMxxX
    398 };
    399 
    400 
    401 /* Forwards */
    402 typedef  struct _SummState  SummState;
    403 static Int TranslateCmd(/*MOD*/SummState* state, const ExtabData* edata);
    404 
    405 
    406 // Take the unwind information extracted by ExtabEntryExtract
    407 // and parse it into frame-unwind instructions.  These are as
    408 // specified in "Table 4, ARM-defined frame-unwinding instructions"
    409 // in the specification document detailed in comments at the top
    410 // of this file.
    411 //
    412 // This reads from |buf[0, +data_size)|.  It checks for overruns of
    413 // the input buffer and returns a negative value if that happens, or
    414 // for any other failure cases.  It returns zero in case of success.
    415 // Whilst reading the input, it dumps the result in |*state|.
    416 static
    417 Int ExtabEntryDecode(/*OUT*/SummState* state, const UChar* buf, SizeT buf_size)
    418 {
    419    if (buf == NULL || buf_size == 0)
    420       return -3;
    421 
    422    MemoryRange mr_in;
    423    Bool ok = MemoryRange__init(&mr_in, buf, buf_size);
    424    if (!ok)
    425       return -2;
    426 
    427 #  define GET_BUF_U8(_lval) \
    428       do { if (!MemoryRange__covers(&mr_in, buf, 1)) \
    429               return -4; \
    430            (_lval) = *(buf++); } while (0)
    431 
    432    const UChar* end = buf + buf_size;
    433 
    434    while (buf < end) {
    435       ExtabData edata;
    436       VG_(bzero_inline)(&edata, sizeof(edata));
    437 
    438       UChar op;
    439       GET_BUF_U8(op);
    440       if ((op & 0xc0) == 0x00) {
    441          // vsp = vsp + (xxxxxx << 2) + 4
    442          edata.cmd  = ARM_EXIDX_CMD_ADD_TO_VSP;
    443          edata.data = (((Int)op & 0x3f) << 2) + 4;
    444       }
    445       else if ((op & 0xc0) == 0x40) {
    446          // vsp = vsp - (xxxxxx << 2) - 4
    447          edata.cmd  = ARM_EXIDX_CMD_SUB_FROM_VSP;
    448          edata.data = (((Int)op & 0x3f) << 2) + 4;
    449       }
    450       else if ((op & 0xf0) == 0x80) {
    451          UChar op2;
    452          GET_BUF_U8(op2);
    453          if (op == 0x80 && op2 == 0x00) {
    454             // Refuse to unwind
    455             edata.cmd = ARM_EXIDX_CMD_REFUSED;
    456          } else {
    457             // Pop up to 12 integer registers under masks {r15-r12},{r11-r4}
    458             edata.cmd  = ARM_EXIDX_CMD_REG_POP;
    459             edata.data = ((op & 0xf) << 8) | op2;
    460             edata.data = edata.data << 4;
    461          }
    462       }
    463       else if ((op & 0xf0) == 0x90) {
    464          if (op == 0x9d || op == 0x9f) {
    465             // 9d: Reserved as prefix for ARM register to register moves
    466             // 9f: Reserved as prefix for Intel Wireless MMX reg to reg moves
    467             edata.cmd = ARM_EXIDX_CMD_RESERVED;
    468          } else {
    469             // Set vsp = r[nnnn]
    470             edata.cmd  = ARM_EXIDX_CMD_REG_TO_SP;
    471             edata.data = op & 0x0f;
    472          }
    473       }
    474       else if ((op & 0xf0) == 0xa0) {
    475          // Pop r4 to r[4+nnn],          or
    476          // Pop r4 to r[4+nnn] and r14
    477          Int nnn    = (op & 0x07);
    478          edata.data = (1 << (nnn + 1)) - 1;
    479          edata.data = edata.data << 4;
    480          if (op & 0x08) edata.data |= 1 << 14;
    481          edata.cmd = ARM_EXIDX_CMD_REG_POP;
    482       }
    483       else if (op == ARM_EXTBL_OP_FINISH) {
    484          // Finish
    485          edata.cmd = ARM_EXIDX_CMD_FINISH;
    486          buf = end;
    487       }
    488       else if (op == 0xb1) {
    489          UChar op2;
    490          GET_BUF_U8(op2);
    491          if (op2 == 0 || (op2 & 0xf0)) {
    492             // Spare
    493             edata.cmd = ARM_EXIDX_CMD_RESERVED;
    494          } else {
    495             // Pop integer registers under mask {r3,r2,r1,r0}
    496             edata.cmd = ARM_EXIDX_CMD_REG_POP;
    497             edata.data = op2 & 0x0f;
    498          }
    499       }
    500       else if (op == 0xb2) {
    501          // vsp = vsp + 0x204 + (uleb128 << 2)
    502          ULong offset = 0;
    503          UChar byte, shift = 0;
    504          do {
    505             GET_BUF_U8(byte);
    506             offset |= (byte & 0x7f) << shift;
    507             shift += 7;
    508          } while ((byte & 0x80) && buf < end);
    509          edata.data = offset * 4 + 0x204;
    510          edata.cmd  = ARM_EXIDX_CMD_ADD_TO_VSP;
    511       }
    512       else if (op == 0xb3 || op == 0xc8 || op == 0xc9) {
    513          // b3: Pop VFP regs D[ssss]    to D[ssss+cccc],    FSTMFDX-ishly
    514          // c8: Pop VFP regs D[16+ssss] to D[16+ssss+cccc], FSTMFDD-ishly
    515          // c9: Pop VFP regs D[ssss]    to D[ssss+cccc],    FSTMFDD-ishly
    516          edata.cmd = ARM_EXIDX_CMD_VFP_POP;
    517          GET_BUF_U8(edata.data);
    518          if (op == 0xc8) edata.data |= ARM_EXIDX_VFP_SHIFT_16;
    519          if (op != 0xb3) edata.data |= ARM_EXIDX_VFP_FSTMD;
    520       }
    521       else if ((op & 0xf8) == 0xb8 || (op & 0xf8) == 0xd0) {
    522          // b8: Pop VFP regs D[8] to D[8+nnn], FSTMFDX-ishly
    523          // d0: Pop VFP regs D[8] to D[8+nnn], FSTMFDD-ishly
    524          edata.cmd  = ARM_EXIDX_CMD_VFP_POP;
    525          edata.data = 0x80 | (op & 0x07);
    526          if ((op & 0xf8) == 0xd0) edata.data |= ARM_EXIDX_VFP_FSTMD;
    527       }
    528       else if (op >= 0xc0 && op <= 0xc5) {
    529          // Intel Wireless MMX pop wR[10]-wr[10+nnn], nnn != 6,7
    530          edata.cmd  = ARM_EXIDX_CMD_WREG_POP;
    531          edata.data = 0xa0 | (op & 0x07);
    532       }
    533       else if (op == 0xc6) {
    534          // Intel Wireless MMX pop wR[ssss] to wR[ssss+cccc]
    535          edata.cmd = ARM_EXIDX_CMD_WREG_POP;
    536          GET_BUF_U8(edata.data);
    537       }
    538       else if (op == 0xc7) {
    539          UChar op2;
    540          GET_BUF_U8(op2);
    541          if (op2 == 0 || (op2 & 0xf0)) {
    542             // Spare
    543             edata.cmd = ARM_EXIDX_CMD_RESERVED;
    544          } else {
    545             // Intel Wireless MMX pop wCGR registers under mask {wCGR3,2,1,0}
    546             edata.cmd = ARM_EXIDX_CMD_WCGR_POP;
    547             edata.data = op2 & 0x0f;
    548          }
    549       }
    550       else {
    551          // Spare
    552          edata.cmd = ARM_EXIDX_CMD_RESERVED;
    553       }
    554 
    555       if (0)
    556          VG_(printf)("  edata:  cmd %08x  data %08x\n",
    557                      (UInt)edata.cmd, (UInt)edata.data);
    558 
    559       Int ret = TranslateCmd ( state, &edata );
    560       if (ret < 0) return ret;
    561    }
    562    return 0;
    563 
    564 # undef GET_BUF_U8
    565 }
    566 
    567 
    568 /*------------------------------------------------------------*/
    569 /*--- (Pass 3 of 3) The EXIDX summariser                   ---*/
    570 /*------------------------------------------------------------*/
    571 
    572 /* In this translation into DiCfSI_m, we're going to have the CFA play
    573    the role of the VSP.  That means that the VSP can be exactly any of
    574    the CFA expressions, viz: {r7,r11,r12,r13) +/- offset.
    575 
    576    All of this would be a lot simpler if the DiCfSI_m representation
    577    was just a bit more expressive and orthogonal.  But it isn't.
    578 
    579    The central difficulty is that, although we can track changes
    580    to the offset of VSP (via vsp_off), we can't deal with assignments
    581    of an entirely new expression to it, because the existing
    582    rules in |cfi| will almost certainly refer to the CFA, and so
    583    changing it will make them invalid.  Hence, below:
    584 
    585    * for the case ARM_EXIDX_CMD_REG_TO_SP we simply disallow
    586      assignment, and hence give up, if any rule refers to CFA
    587 
    588    * for the case ARM_EXIDX_CMD_REG_POP, the SP (hence, VSP) is
    589      updated by the pop, give up.
    590 
    591    This is an ugly hack to work around not having a better (LUL-like)
    592    expression representation.  That said, these restrictions don't
    593    appear to be a big problem in practice.
    594 */
    595 
    596 struct _SummState {
    597    // The DiCfSI_m under construction
    598    DiCfSI_m   cfi;
    599    Int        vsp_off;
    600    // For generating CFI register expressions, if needed.
    601    DebugInfo* di;
    602 };
    603 
    604 
    605 /* Generate a trivial CfiExpr, for the ARM(32) integer register
    606    numbered |gprNo|.  First ensure this DebugInfo has a cfsi_expr
    607    array in which to park it.  Returns -1 if |gprNo| cannot be
    608    represented, otherwise returns a value >= 0. */
    609 static
    610 Int gen_CfiExpr_CfiReg_ARM_GPR ( /*MB_MOD*/DebugInfo* di, UInt gprNo )
    611 {
    612    CfiReg creg = Creg_INVALID;
    613    switch (gprNo) {
    614       case 13: creg = Creg_ARM_R13; break;
    615       case 12: creg = Creg_ARM_R12; break;
    616       case 15: creg = Creg_ARM_R15; break;
    617       case 14: creg = Creg_ARM_R14; break;
    618       case 7:  creg = Creg_ARM_R7;  break;
    619       default: break;
    620    }
    621    if (creg == Creg_INVALID) {
    622       return -1;
    623    }
    624    if (!di->cfsi_exprs) {
    625       di->cfsi_exprs = VG_(newXA)( ML_(dinfo_zalloc), "di.gCCAG",
    626                                    ML_(dinfo_free), sizeof(CfiExpr) );
    627    }
    628    Int res = ML_(CfiExpr_CfiReg)( di->cfsi_exprs, creg );
    629    vg_assert(res >= 0);
    630    return res;
    631 }
    632 
    633 
    634 /* Given a DiCfSI_m, find the _how/_off pair for the given ARM(32) GPR
    635    number inside |cfsi_m|, or return NULL for both if that register
    636    number is not represented. */
    637 static
    638 void maybeFindExprForRegno( /*OUT*/UChar** howPP, /*OUT*/Int** offPP,
    639                             DiCfSI_m* cfsi_m, Int regNo )
    640 {
    641    switch (regNo) {
    642       case 15: *howPP = &cfsi_m->ra_how;  *offPP = &cfsi_m->ra_off;  return;
    643       case 14: *howPP = &cfsi_m->r14_how; *offPP = &cfsi_m->r14_off; return;
    644       case 13: *howPP = &cfsi_m->r13_how; *offPP = &cfsi_m->r13_off; return;
    645       case 12: *howPP = &cfsi_m->r12_how; *offPP = &cfsi_m->r12_off; return;
    646       case 11: *howPP = &cfsi_m->r11_how; *offPP = &cfsi_m->r11_off; return;
    647       case 7:  *howPP = &cfsi_m->r7_how;  *offPP = &cfsi_m->r7_off;  return;
    648       default: break;
    649    }
    650    *howPP = NULL; *offPP = NULL;
    651 }
    652 
    653 
    654 /* Set cfi.cfa_{how,off} so as to be a copy of the expression denoted
    655    by (how,off), if it is possible to do so.  Returns True on
    656    success. */
    657 static
    658 Bool setCFAfromCFIR( /*MOD*/DiCfSI_m* cfi, XArray*/*CfiExpr*/ cfsi_exprs,
    659                      UChar how, Int off )
    660 {
    661    switch (how) {
    662       case CFIR_EXPR:
    663          if (!cfsi_exprs) return False;
    664          CfiExpr* e = (CfiExpr*)VG_(indexXA)(cfsi_exprs, off);
    665          if (e->tag != Cex_CfiReg) return False;
    666          if (e->Cex.CfiReg.reg == Creg_ARM_R7) {
    667             cfi->cfa_how = CFIC_ARM_R7REL;
    668             cfi->cfa_off = 0;
    669             return True;
    670          }
    671          ML_(ppCfiExpr)(cfsi_exprs, off);
    672          vg_assert(0);
    673       default:
    674          break;
    675    }
    676    VG_(printf)("setCFAfromCFIR: FAIL: how %d off %d\n", (Int)how, (Int)off);
    677    vg_assert(0);
    678    return False;
    679 }
    680 
    681 
    682 #define ARM_EXBUF_START(x) (((x) >> 4) & 0x0f)
    683 #define ARM_EXBUF_COUNT(x) ((x) & 0x0f)
    684 #define ARM_EXBUF_END(x)   (ARM_EXBUF_START(x) + ARM_EXBUF_COUNT(x))
    685 
    686 
    687 static Bool mentionsCFA ( DiCfSI_m* cfi )
    688 {
    689 #  define MENTIONS_CFA(_how) ((_how) == CFIR_CFAREL || (_how) == CFIR_MEMCFAREL)
    690    if (MENTIONS_CFA(cfi->ra_how))  return True;
    691    if (MENTIONS_CFA(cfi->r14_how)) return True;
    692    if (MENTIONS_CFA(cfi->r13_how)) return True;
    693    if (MENTIONS_CFA(cfi->r12_how)) return True;
    694    if (MENTIONS_CFA(cfi->r11_how)) return True;
    695    if (MENTIONS_CFA(cfi->r7_how))  return True;
    696    return False;
    697 #  undef MENTIONS_CFA
    698 }
    699 
    700 
    701 // Translate command from extab_data to command for Module.
    702 static
    703 Int TranslateCmd(/*MOD*/SummState* state, const ExtabData* edata)
    704 {
    705    /* Stay sane: check that the CFA has the expected form. */
    706    vg_assert(state);
    707    switch (state->cfi.cfa_how) {
    708       case CFIC_ARM_R13REL: case CFIC_ARM_R12REL:
    709       case CFIC_ARM_R11REL: case CFIC_ARM_R7REL: break;
    710       default: vg_assert(0);
    711    }
    712 
    713    if (0) {
    714       VG_(printf)("  TranslateCmd: ");
    715       ppExtabData(edata);
    716       VG_(printf)("\n");
    717    }
    718 
    719    Int ret = 0;
    720    switch (edata->cmd) {
    721       case ARM_EXIDX_CMD_FINISH:
    722          /* Copy LR to PC if there isn't currently a rule for PC in force. */
    723          if (state->cfi.ra_how == CFIR_UNKNOWN) {
    724             if (state->cfi.r14_how == CFIR_UNKNOWN) {
    725                state->cfi.ra_how = CFIR_EXPR;
    726                state->cfi.ra_off = gen_CfiExpr_CfiReg_ARM_GPR(state->di, 14);
    727                vg_assert(state->cfi.ra_off >= 0);
    728             } else {
    729                state->cfi.ra_how = state->cfi.r14_how;
    730                state->cfi.ra_off = state->cfi.r14_off;
    731             }
    732          }
    733          break;
    734       case ARM_EXIDX_CMD_SUB_FROM_VSP:
    735          state->vsp_off -= (Int)(edata->data);
    736          break;
    737       case ARM_EXIDX_CMD_ADD_TO_VSP:
    738          state->vsp_off += (Int)(edata->data);
    739          break;
    740       case ARM_EXIDX_CMD_REG_POP: {
    741          UInt i;
    742          for (i = 0; i < 16; i++) {
    743             if (edata->data & (1 << i)) {
    744                // See if we're summarising for int register |i|.  If so,
    745                // describe how to pull it off the stack.  The cast of |i| is
    746                // a bit of a kludge but works because DW_REG_ARM_Rn has the
    747                // value |n|, for 0 <= |n| <= 15 -- that is, for the ARM
    748                // general-purpose registers.
    749                UChar* rX_howP = NULL;
    750                Int*   rX_offP = NULL;
    751                maybeFindExprForRegno(&rX_howP, &rX_offP, &state->cfi, i);
    752                if (rX_howP) {
    753                   vg_assert(rX_offP);
    754                   /* rX_howP and rX_offP point at one of the rX fields
    755                      in |state->cfi|.  Hence the following assignments
    756                      are really updating |state->cfi|. */
    757                   *rX_howP = CFIR_MEMCFAREL;
    758                   *rX_offP = state->vsp_off;
    759                } else {
    760                   /* We're not tracking this register, so ignore it. */
    761                   vg_assert(!rX_offP);
    762                }
    763                state->vsp_off += 4;
    764             }
    765          }
    766          /* Set cfa in case the SP got popped. */
    767          if (edata->data & (1 << 13)) {
    768             //  vsp = curr_rules_.mR13expr;
    769             //state->cfi.cfa_how =
    770             //state->cfi.cfa_off =
    771             //state->vsp_off = 0;
    772             // If this happens, it would make the existing CFA references
    773             // in the summary invalid.  So give up instead.
    774             goto cant_summarise;
    775          }
    776          break;
    777          }
    778       case ARM_EXIDX_CMD_REG_TO_SP: {
    779          /* We're generating a new value for the CFA/VSP here.  Hence,
    780             if the summary already refers to the CFA at all, we can't
    781             go any further, and have to abandon summarisation. */
    782          if (mentionsCFA(&state->cfi))
    783             goto cant_summarise;
    784          vg_assert(edata->data < 16);
    785          Int reg_no = edata->data;
    786          // Same comment as above, re the casting of |reg_no|, applies.
    787          UChar* rX_howP = NULL;
    788          Int*   rX_offP = NULL;
    789          maybeFindExprForRegno(&rX_howP, &rX_offP, &state->cfi, reg_no);
    790          if (rX_howP) {
    791             vg_assert(rX_offP);
    792             if (*rX_howP == CFIR_UNKNOWN) {
    793                //curr_rules_.mR13expr = LExpr(LExpr::NODEREF, reg_no, 0);
    794                Int expr_ix = gen_CfiExpr_CfiReg_ARM_GPR(state->di, reg_no);
    795                if (expr_ix >= 0) {
    796                   state->cfi.r13_how = CFIR_EXPR;
    797                   state->cfi.r13_off = expr_ix;
    798                } else {
    799                   goto cant_summarise;
    800                }
    801             } else {
    802                //curr_rules_.mR13expr = *reg_exprP;
    803                state->cfi.r13_how = *rX_howP;
    804                state->cfi.r13_off = *rX_offP;
    805             }
    806             //vsp = curr_rules_.mR13expr;
    807             Bool ok = setCFAfromCFIR( &state->cfi, state->di->cfsi_exprs,
    808                                       state->cfi.r13_how, state->cfi.r13_off );
    809             if (!ok) goto cant_summarise;
    810             state->vsp_off = 0;
    811          } else {
    812             vg_assert(!rX_offP);
    813          }
    814          break;
    815       }
    816       case ARM_EXIDX_CMD_VFP_POP: {
    817          /* Don't recover VFP registers, but be sure to adjust the stack
    818             pointer. */
    819          UInt i;
    820          for (i = ARM_EXBUF_START(edata->data);
    821               i <= ARM_EXBUF_END(edata->data); i++) {
    822             state->vsp_off += 8;
    823          }
    824          if (!(edata->data & ARM_EXIDX_VFP_FSTMD)) {
    825             state->vsp_off += 4;
    826          }
    827          break;
    828       }
    829       case ARM_EXIDX_CMD_WREG_POP: {
    830          UInt i;
    831          for (i = ARM_EXBUF_START(edata->data);
    832               i <= ARM_EXBUF_END(edata->data); i++) {
    833             state->vsp_off += 8;
    834          }
    835          break;
    836       }
    837       case ARM_EXIDX_CMD_WCGR_POP: {
    838          UInt i;
    839          // Pop wCGR registers under mask {wCGR3,2,1,0}, hence "i < 4"
    840          for (i = 0; i < 4; i++) {
    841             if (edata->data & (1 << i)) {
    842                state->vsp_off += 4;
    843             }
    844          }
    845          break;
    846       }
    847       case ARM_EXIDX_CMD_REFUSED:
    848       case ARM_EXIDX_CMD_RESERVED:
    849          ret = -1;
    850          break;
    851    }
    852    return ret;
    853 
    854  cant_summarise:
    855    return -10;
    856 }
    857 
    858 
    859 /* Initialise the EXIDX summariser, by writing initial values in |state|. */
    860 static
    861 void AddStackFrame ( /*OUT*/SummState* state,
    862                      DebugInfo* di )
    863 {
    864    VG_(bzero_inline)(state, sizeof(*state));
    865    state->vsp_off = 0;
    866    state->di      = di;
    867    /* Initialise the DiCfSI_m that we are building. */
    868    state->cfi.cfa_how = CFIC_ARM_R13REL;
    869    state->cfi.cfa_off = 0;
    870    state->cfi.ra_how  = CFIR_UNKNOWN;
    871    state->cfi.r14_how = CFIR_UNKNOWN;
    872    state->cfi.r13_how = CFIR_UNKNOWN;
    873    state->cfi.r12_how = CFIR_UNKNOWN;
    874    state->cfi.r11_how = CFIR_UNKNOWN;
    875    state->cfi.r7_how  = CFIR_UNKNOWN;
    876 }
    877 
    878 static
    879 void SubmitStackFrame( /*MOD*/DebugInfo* di,
    880                        SummState* state, Addr avma, SizeT len )
    881 {
    882    // JRS: I'm really not sure what this means, or if it is necessary
    883    // return address always winds up in pc
    884    //stack_frame_entry_->initial_rules[ustr__ZDra()] // ".ra"
    885    //  = stack_frame_entry_->initial_rules[ustr__pc()];
    886    // maybe don't need to do anything here?
    887 
    888    // the final value of vsp is the new value of sp.
    889    switch (state->cfi.cfa_how) {
    890       case CFIC_ARM_R13REL: case CFIC_ARM_R12REL:
    891       case CFIC_ARM_R11REL: case CFIC_ARM_R7REL: break;
    892       default: vg_assert(0);
    893    }
    894    state->cfi.r13_how = CFIR_CFAREL;
    895    state->cfi.r13_off = state->vsp_off;
    896 
    897    // Finally, add the completed RuleSet to the SecMap
    898    if (len > 0) {
    899 
    900       // Futz with the rules for r4 .. r11 in the same way as happens
    901       // with the CFI summariser:
    902       /* Mark callee-saved registers (r4 .. r11) as unchanged, if there is
    903        no other information about them.  FIXME: do this just once, at
    904        the point where the ruleset is committed. */
    905       if (state->cfi.r7_how == CFIR_UNKNOWN) {
    906          state->cfi.r7_how = CFIR_SAME;
    907          state->cfi.r7_off = 0;
    908       }
    909       if (state->cfi.r11_how == CFIR_UNKNOWN) {
    910          state->cfi.r11_how = CFIR_SAME;
    911          state->cfi.r11_off = 0;
    912       }
    913       if (state->cfi.r12_how == CFIR_UNKNOWN) {
    914          state->cfi.r12_how = CFIR_SAME;
    915          state->cfi.r12_off = 0;
    916       }
    917       if (state->cfi.r14_how == CFIR_UNKNOWN) {
    918          state->cfi.r14_how = CFIR_SAME;
    919          state->cfi.r14_off = 0;
    920       }
    921 
    922       // And add them
    923       ML_(addDiCfSI)(di, avma, len, &state->cfi);
    924       if (di->trace_cfi)
    925          ML_(ppDiCfSI)(di->cfsi_exprs, avma, len, &state->cfi);
    926    }
    927 }
    928 
    929 
    930 /*------------------------------------------------------------*/
    931 /*--- Top level                                            ---*/
    932 /*------------------------------------------------------------*/
    933 
    934 void ML_(read_exidx) ( /*MOD*/DebugInfo* di,
    935                        UChar*   exidx_img, SizeT exidx_size,
    936                        UChar*   extab_img, SizeT extab_size,
    937                        Addr     text_last_svma,
    938                        PtrdiffT text_bias )
    939 {
    940    if (di->trace_cfi)
    941       VG_(printf)("BEGIN ML_(read_exidx) exidx_img=[%p, +%lu) "
    942                   "extab_img=[%p, +%lu) text_last_svma=%lx text_bias=%lx\n",
    943                   exidx_img, exidx_size, extab_img, extab_size,
    944                   text_last_svma, text_bias);
    945    Bool ok;
    946    MemoryRange mr_exidx, mr_extab;
    947    ok =       MemoryRange__init(&mr_exidx, exidx_img, exidx_size);
    948    ok = ok && MemoryRange__init(&mr_extab, extab_img, extab_size);
    949    if (!ok) {
    950       complain(".exidx or .extab image area wraparound");
    951       return;
    952    }
    953 
    954    const ExidxEntry* start_img = (const ExidxEntry*)exidx_img;
    955    const ExidxEntry* end_img   = (const ExidxEntry*)(exidx_img + exidx_size);
    956 
    957    if (VG_(clo_verbosity) > 1)
    958       VG_(message)(Vg_DebugMsg, "  Reading EXIDX entries: %lu available\n",
    959                    exidx_size / sizeof(ExidxEntry) );
    960 
    961    // Iterate over each of the EXIDX entries (pairs of 32-bit words).
    962    // These occupy the entire .exidx section.
    963    UWord n_attempted = 0, n_successful = 0;
    964 
    965    const ExidxEntry* entry_img;
    966    for (entry_img = start_img; entry_img < end_img; ++entry_img) {
    967 
    968       n_attempted++;
    969       // Figure out the code address range that this table entry_img is
    970       // associated with.
    971       Addr avma = (Addr)Prel31ToAddr(&entry_img->addr);
    972       if (di->trace_cfi)
    973          VG_(printf)("XXX1 entry: entry->addr 0x%lx, avma 0x%lx\n",
    974                      (UWord)entry_img->addr, avma);
    975 
    976       Addr next_avma;
    977       if (entry_img < end_img - 1) {
    978          next_avma = (Addr)Prel31ToAddr(&(entry_img+1)->addr);
    979       } else {
    980          // This is the last EXIDX entry in the sequence, so we don't
    981          // have an address for the start of the next function, to limit
    982          // this one.  Instead use the address of the last byte of the
    983          // text section associated with this .exidx section, that we
    984          // have been given.  So as to avoid junking up the CFI unwind
    985          // tables with absurdly large address ranges in the case where
    986          // text_last_svma_ is wrong, only use the value if it is nonzero
    987          // and within one page of |svma|.  Otherwise assume a length of 1.
    988          //
    989          // In some cases, gcc has been observed to finish the exidx
    990          // section with an entry of length 1 marked CANT_UNWIND,
    991          // presumably exactly for the purpose of giving a definite
    992          // length for the last real entry, without having to look at
    993          // text segment boundaries.
    994          Addr text_last_avma = text_last_svma + text_bias;
    995 
    996          Bool plausible;
    997          Addr maybe_next_avma = text_last_avma + 1;
    998          if (maybe_next_avma > avma && maybe_next_avma - avma <= 4096) {
    999             next_avma = maybe_next_avma;
   1000             plausible = True;
   1001          } else {
   1002             next_avma = avma + 1;
   1003             plausible = False;
   1004          }
   1005 
   1006          if (!plausible && avma != text_last_avma + 1) {
   1007             HChar buf[100];
   1008             VG_(snprintf)(buf, sizeof(buf),
   1009                           "Implausible EXIDX last entry size %u"
   1010                           "; using 1 instead.", (UInt)(text_last_avma - avma));
   1011             buf[sizeof(buf)-1] = 0;
   1012             complain(buf);
   1013          }
   1014       }
   1015 
   1016       // Extract the unwind info into |buf|.  This might fail for
   1017       // various reasons.  It involves reading both the .exidx and
   1018       // .extab sections.  All accesses to those sections are
   1019       // bounds-checked.
   1020       if (di->trace_cfi)
   1021          VG_(printf)("XXX1 entry is for AVMA 0x%lx 0x%lx\n",
   1022                      avma, next_avma-1);
   1023       UChar buf[ARM_EXIDX_TABLE_LIMIT];
   1024       SizeT buf_used = 0;
   1025       ExExtractResult res
   1026          = ExtabEntryExtract(&mr_exidx, &mr_extab,
   1027                              entry_img, buf, sizeof(buf), &buf_used);
   1028       if (res != ExSuccess) {
   1029          // Couldn't extract the unwind info, for some reason.  Move on.
   1030          switch (res) {
   1031             case ExInBufOverflow:
   1032                complain("ExtabEntryExtract: .exidx/.extab section overrun");
   1033                break;
   1034             case ExOutBufOverflow:
   1035                complain("ExtabEntryExtract: bytecode buffer overflow");
   1036                break;
   1037             case ExCantUnwind:
   1038                // Some functions are marked CantUnwind by the compiler.
   1039                // Don't record these as attempted, since that's just
   1040                // confusing, and failure to summarise them is not the fault
   1041                // of this code.
   1042                n_attempted--;
   1043                if (0)
   1044                   complain("ExtabEntryExtract: function is marked CANT_UNWIND");
   1045                break;
   1046             case ExCantRepresent:
   1047                complain("ExtabEntryExtract: bytecode can't be represented");
   1048                break;
   1049             case ExInvalid:
   1050                complain("ExtabEntryExtract: index table entry is invalid");
   1051                break;
   1052             default: {
   1053                HChar mbuf[100];
   1054                VG_(snprintf)(mbuf, sizeof(mbuf),
   1055                              "ExtabEntryExtract: unknown error: %d", (Int)res);
   1056                buf[sizeof(mbuf)-1] = 0;
   1057                complain(mbuf);
   1058                break;
   1059             }
   1060          }
   1061          continue;
   1062       }
   1063 
   1064       // Finally, work through the unwind instructions in |buf| and
   1065       // create CFI entries that Valgrind can use.  This can also fail.
   1066       // First, initialise the summariser's running state, into which
   1067       // ExtabEntryDecode will write the CFI entries.
   1068 
   1069       SummState state;
   1070       AddStackFrame( &state, di );
   1071       Int ret = ExtabEntryDecode( &state, buf, buf_used );
   1072       if (ret < 0) {
   1073          /* Failed summarisation.  Ignore and move on. */
   1074          HChar mbuf[100];
   1075          VG_(snprintf)(mbuf, sizeof(mbuf),
   1076                        "ExtabEntryDecode: failed with error code: %d", ret);
   1077          mbuf[sizeof(mbuf)-1] = 0;
   1078          complain(mbuf);
   1079       } else {
   1080          /* Successful summarisation.  Add it to the collection. */
   1081          SubmitStackFrame( di, &state, avma, next_avma - avma );
   1082          n_successful++;
   1083       }
   1084 
   1085    } /* iterating over .exidx */
   1086 
   1087    if (VG_(clo_verbosity) > 1)
   1088       VG_(message)(Vg_DebugMsg,
   1089                    "  Reading EXIDX entries: %lu attempted, %lu successful\n",
   1090                    n_attempted, n_successful);
   1091 }
   1092 
   1093 #endif /* defined(VGA_arm) */
   1094 
   1095 /*--------------------------------------------------------------------*/
   1096 /*--- end                                              readexidx.c ---*/
   1097 /*--------------------------------------------------------------------*/
   1098