1 /* -*- mode: C; c-basic-offset: 3; -*- */
3 /*--------------------------------------------------------------------*/
4 /*--- Reading of ARM(32) EXIDX unwind information readexidx.c ---*/
5 /*--------------------------------------------------------------------*/
8 This file is part of Valgrind, a dynamic binary instrumentation
11 Copyright (C) 2014-2017 Mozilla Foundation
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.
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.
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, see <http://www.gnu.org/licenses/>.
26 The GNU General Public License is contained in the file COPYING.
29 /* libunwind - a platform-independent unwind library
30 Copyright 2011 Linaro Limited
32 This file is part of libunwind.
34 Permission is hereby granted, free of charge, to any person obtaining
35 a copy of this software and associated documentation files (the
36 "Software"), to deal in the Software without restriction, including
37 without limitation the rights to use, copy, modify, merge, publish,
38 distribute, sublicense, and/or sell copies of the Software, and to
39 permit persons to whom the Software is furnished to do so, subject to
40 the following conditions:
42 The above copyright notice and this permission notice shall be
43 included in all copies or substantial portions of the Software.
45 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
46 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
47 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
48 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
49 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
50 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
51 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
54 // Copyright (c) 2010 Google Inc.
55 // All rights reserved.
57 // Redistribution and use in source and binary forms, with or without
58 // modification, are permitted provided that the following conditions are
61 // * Redistributions of source code must retain the above copyright
62 // notice, this list of conditions and the following disclaimer.
63 // * Redistributions in binary form must reproduce the above
64 // copyright notice, this list of conditions and the following disclaimer
65 // in the documentation and/or other materials provided with the
67 // * Neither the name of Google Inc. nor the names of its
68 // contributors may be used to endorse or promote products derived from
69 // this software without specific prior written permission.
71 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
72 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
73 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
74 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
75 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
76 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
77 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
78 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
79 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
80 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
81 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
84 // Derived originally from libunwind, with very extensive modifications.
85 /* Contributed by Julian Seward <jseward@acm.org> */
88 // This file translates EXIDX unwind information into the same format
89 // that Valgrind uses for CFI information. Hence Valgrind's CFI
90 // unwinding abilities also become usable for EXIDX.
92 // See: "Exception Handling ABI for the ARM Architecture", ARM IHI 0038A
93 // http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038a/IHI0038A_ehabi.pdf
95 // EXIDX data is presented in two parts:
97 // * an index table. This contains two words per routine,
98 // the first of which identifies the routine, and the second
99 // of which is a reference to the unwind bytecode. If the
100 // bytecode is very compact -- 3 bytes or less -- it can be
101 // stored directly in the second word.
103 // * an area containing the unwind bytecodes.
105 // General flow is: ML_(read_exidx) iterates over all
106 // of the index table entries (pairs). For each entry, it:
108 // * calls ExtabEntryExtract to copy the bytecode out into
109 // an intermediate buffer.
111 // * uses ExtabEntryDecode to parse the intermediate
112 // buffer. Each bytecode instruction is bundled into a
113 // arm_ex_to_module::extab_data structure, and handed to ..
115 // * .. TranslateCmd, which generates the pseudo-CFI
116 // records that Valgrind stores.
118 // This file is derived from the following files in the Mozilla tree
119 // toolkit/crashreporter/google-breakpad:
120 // src/common/arm_ex_to_module.cc
121 // src/common/arm_ex_reader.cc
126 #include "pub_core_basics.h"
127 #include "pub_core_libcbase.h"
128 #include "pub_core_libcprint.h"
129 #include "pub_core_libcassert.h"
130 #include "pub_core_options.h"
132 #include "priv_storage.h"
133 #include "priv_readexidx.h"
136 static void complain ( const HChar
* str
)
138 if (!VG_(clo_xml
) && VG_(clo_verbosity
) > 1)
139 VG_(message
)(Vg_UserMsg
,
140 " Warning: whilst reading EXIDX: %s\n", str
);
144 /*------------------------------------------------------------*/
145 /*--- MemoryRange ---*/
146 /*------------------------------------------------------------*/
148 typedef struct { Addr start
; SizeT len
; } MemoryRange
;
150 /* Initialise |mr| for [start .. start+len). Zero ranges are allowed,
151 but wraparounds are not. Returns True on success. */
152 static Bool
MemoryRange__init ( /*OUT*/MemoryRange
* mr
,
153 const void* startV
, SizeT len
)
155 VG_(memset
)(mr
, 0, sizeof(*mr
));
156 /* This relies on Addr being unsigned. */
157 Addr start
= (Addr
)startV
;
158 if (len
> 0 && start
+ len
- 1 < start
) {
166 static Bool
MemoryRange__covers ( MemoryRange
* mr
,
167 const void* startV
, SizeT len
)
173 Addr start
= (Addr
)startV
;
174 return start
>= mr
->start
&& start
+ len
- 1 <= mr
->start
+ mr
->len
- 1;
178 /*------------------------------------------------------------*/
179 /*--- (Pass 1 of 3) The EXIDX extractor ---*/
180 /*------------------------------------------------------------*/
182 #define ARM_EXIDX_CANT_UNWIND 0x00000001
183 #define ARM_EXIDX_COMPACT 0x80000000
184 #define ARM_EXTBL_OP_FINISH 0xb0
185 #define ARM_EXIDX_TABLE_LIMIT (255*4)
187 /* These are in the ARM-defined format, so their layout is important. */
189 struct { UInt addr
; UInt data
; }
195 ExSuccess
=1, // success
196 ExInBufOverflow
, // out-of-range while reading .exidx
197 ExOutBufOverflow
, // output buffer is too small
198 ExCantUnwind
, // this function is marked CANT_UNWIND
199 ExCantRepresent
, // entry valid, but we can't represent it
200 ExInvalid
// entry is invalid
205 /* Helper function for fishing bits out of the EXIDX representation. */
206 static const void* Prel31ToAddr(const void* addr
)
208 UInt offset32
= *(const UInt
*)addr
;
209 // sign extend offset32[30:0] to 64 bits -- copy bit 30 to positions
211 ULong offset64
= offset32
;
212 if (offset64
& (1ULL << 30))
213 offset64
|= 0xFFFFFFFF80000000ULL
;
215 offset64
&= 0x000000007FFFFFFFULL
;
216 return ((const UChar
*)addr
) + (UWord
)offset64
;
220 // Extract unwind bytecode for the function denoted by |entry| into |buf|,
221 // and return the number of bytes of |buf| written, along with a code
222 // indicating the outcome.
224 ExExtractResult
ExtabEntryExtract ( MemoryRange
* mr_exidx
,
225 MemoryRange
* mr_extab
,
226 const ExidxEntry
* entry
,
227 UChar
* buf
, SizeT buf_size
,
228 /*OUT*/SizeT
* buf_used
)
232 ok
= MemoryRange__init(&mr_out
, buf
, buf_size
);
233 if (!ok
) return ExOutBufOverflow
;
237 # define PUT_BUF_U8(_byte) \
238 do { if (!MemoryRange__covers(&mr_out, &buf[*buf_used], 1)) \
239 return ExOutBufOverflow; \
240 buf[(*buf_used)++] = (_byte); } while (0)
242 # define GET_EX_U32(_lval, _addr, _mr) \
243 do { if (!MemoryRange__covers((_mr), (const void*)(_addr), 4)) \
244 return ExInBufOverflow; \
245 (_lval) = *(const UInt*)(_addr); } while (0)
247 # define GET_EXIDX_U32(_lval, _addr) \
248 GET_EX_U32(_lval, _addr, mr_exidx)
250 # define GET_EXTAB_U32(_lval, _addr) \
251 GET_EX_U32(_lval, _addr, mr_extab)
254 GET_EXIDX_U32(data
, &entry
->data
);
256 // A function can be marked CANT_UNWIND if (eg) it is known to be
257 // at the bottom of the stack.
258 if (data
== ARM_EXIDX_CANT_UNWIND
)
261 UInt pers
; // personality number
262 UInt extra
; // number of extra data words required
263 UInt extra_allowed
; // number of extra data words allowed
264 const UInt
* extbl_data
; // the handler entry, if not inlined
266 if (data
& ARM_EXIDX_COMPACT
) {
267 // The handler table entry has been inlined into the index table entry.
268 // In this case it can only be an ARM-defined compact model, since
269 // bit 31 is 1. Only personalities 0, 1 and 2 are defined for the
270 // ARM compact model, but 1 and 2 are "Long format" and may require
271 // extra data words. Hence the allowable personalities here are:
272 // personality 0, in which case 'extra' has no meaning
273 // personality 1, with zero extra words
274 // personality 2, with zero extra words
276 pers
= (data
>> 24) & 0x0F;
277 extra
= (data
>> 16) & 0xFF;
281 // The index table entry is a pointer to the handler entry. Note
282 // that Prel31ToAddr will read the given address, but we already
283 // range-checked above.
284 extbl_data
= Prel31ToAddr(&entry
->data
);
285 GET_EXTAB_U32(data
, extbl_data
);
286 if (!(data
& ARM_EXIDX_COMPACT
)) {
287 // This denotes a "generic model" handler. That will involve
288 // executing arbitrary machine code, which is something we
289 // can't represent here; hence reject it.
290 return ExCantRepresent
;
292 // So we have a compact model representation. Again, 3 possible
293 // personalities, but this time up to 255 allowable extra words.
294 pers
= (data
>> 24) & 0x0F;
295 extra
= (data
>> 16) & 0xFF;
300 // Now look at the handler table entry. The first word is |data|
301 // and subsequent words start at |*extbl_data|. The number of
302 // extra words to use is |extra|, provided that the personality
303 // allows extra words. Even if it does, none may be available --
304 // extra_allowed is the maximum number of extra words allowed. */
306 // "Su16" in the documentation -- 3 unwinding insn bytes
307 // |extra| has no meaning here; instead that byte is an unwind-info byte
308 PUT_BUF_U8(data
>> 16);
309 PUT_BUF_U8(data
>> 8);
312 else if ((pers
== 1 || pers
== 2) && extra
<= extra_allowed
) {
313 // "Lu16" or "Lu32" respectively -- 2 unwinding insn bytes,
314 // and up to 255 extra words.
315 PUT_BUF_U8(data
>> 8);
318 for (j
= 0; j
< extra
; j
++) {
319 GET_EXTAB_U32(data
, extbl_data
);
321 PUT_BUF_U8(data
>> 24);
322 PUT_BUF_U8(data
>> 16);
323 PUT_BUF_U8(data
>> 8);
324 PUT_BUF_U8(data
>> 0);
328 // The entry is invalid.
332 // Make sure the entry is terminated with "FINISH"
333 if (*buf_used
> 0 && buf
[(*buf_used
) - 1] != ARM_EXTBL_OP_FINISH
)
334 PUT_BUF_U8(ARM_EXTBL_OP_FINISH
);
338 # undef GET_EXTAB_U32
339 # undef GET_EXIDX_U32
345 /*------------------------------------------------------------*/
346 /*--- (Pass 2 of 3) The EXIDX decoder ---*/
347 /*------------------------------------------------------------*/
349 /* This (ExtabData) is an intermediate structure, used to carry
350 information from the decoder (pass 2) to the summariser (pass 3).
351 I don't think its layout is important. */
354 ARM_EXIDX_CMD_FINISH
=0x100,
355 ARM_EXIDX_CMD_SUB_FROM_VSP
,
356 ARM_EXIDX_CMD_ADD_TO_VSP
,
357 ARM_EXIDX_CMD_REG_POP
,
358 ARM_EXIDX_CMD_REG_TO_SP
,
359 ARM_EXIDX_CMD_VFP_POP
,
360 ARM_EXIDX_CMD_WREG_POP
,
361 ARM_EXIDX_CMD_WCGR_POP
,
362 ARM_EXIDX_CMD_RESERVED
,
363 ARM_EXIDX_CMD_REFUSED
367 static const HChar
* showExtabCmd ( ExtabCmd cmd
) {
369 case ARM_EXIDX_CMD_FINISH
: return "FINISH";
370 case ARM_EXIDX_CMD_SUB_FROM_VSP
: return "SUB_FROM_VSP";
371 case ARM_EXIDX_CMD_ADD_TO_VSP
: return "ADD_TO_VSP";
372 case ARM_EXIDX_CMD_REG_POP
: return "REG_POP";
373 case ARM_EXIDX_CMD_REG_TO_SP
: return "REG_TO_SP";
374 case ARM_EXIDX_CMD_VFP_POP
: return "VFP_POP";
375 case ARM_EXIDX_CMD_WREG_POP
: return "WREG_POP";
376 case ARM_EXIDX_CMD_WCGR_POP
: return "WCGR_POP";
377 case ARM_EXIDX_CMD_RESERVED
: return "RESERVED";
378 case ARM_EXIDX_CMD_REFUSED
: return "REFUSED";
379 default: return "???";
385 struct { ExtabCmd cmd
; UInt data
; }
388 static void ppExtabData ( const ExtabData
* etd
) {
389 VG_(printf
)("ExtabData{%-12s 0x%08x}", showExtabCmd(etd
->cmd
), etd
->data
);
393 enum extab_cmd_flags
{
394 ARM_EXIDX_VFP_SHIFT_16
= 1 << 16,
395 ARM_EXIDX_VFP_FSTMD
= 1 << 17, // distinguishes FSTMxxD from FSTMxxX
400 typedef struct _SummState SummState
;
401 static Int
TranslateCmd(/*MOD*/SummState
* state
, const ExtabData
* edata
);
404 // Take the unwind information extracted by ExtabEntryExtract
405 // and parse it into frame-unwind instructions. These are as
406 // specified in "Table 4, ARM-defined frame-unwinding instructions"
407 // in the specification document detailed in comments at the top
410 // This reads from |buf[0, +data_size)|. It checks for overruns of
411 // the input buffer and returns a negative value if that happens, or
412 // for any other failure cases. It returns zero in case of success.
413 // Whilst reading the input, it dumps the result in |*state|.
415 Int
ExtabEntryDecode(/*OUT*/SummState
* state
, const UChar
* buf
, SizeT buf_size
)
417 if (buf
== NULL
|| buf_size
== 0)
421 Bool ok
= MemoryRange__init(&mr_in
, buf
, buf_size
);
425 # define GET_BUF_U8(_lval) \
426 do { if (!MemoryRange__covers(&mr_in, buf, 1)) \
428 (_lval) = *(buf++); } while (0)
430 const UChar
* end
= buf
+ buf_size
;
434 VG_(bzero_inline
)(&edata
, sizeof(edata
));
438 if ((op
& 0xc0) == 0x00) {
439 // vsp = vsp + (xxxxxx << 2) + 4
440 edata
.cmd
= ARM_EXIDX_CMD_ADD_TO_VSP
;
441 edata
.data
= (((Int
)op
& 0x3f) << 2) + 4;
443 else if ((op
& 0xc0) == 0x40) {
444 // vsp = vsp - (xxxxxx << 2) - 4
445 edata
.cmd
= ARM_EXIDX_CMD_SUB_FROM_VSP
;
446 edata
.data
= (((Int
)op
& 0x3f) << 2) + 4;
448 else if ((op
& 0xf0) == 0x80) {
451 if (op
== 0x80 && op2
== 0x00) {
453 edata
.cmd
= ARM_EXIDX_CMD_REFUSED
;
455 // Pop up to 12 integer registers under masks {r15-r12},{r11-r4}
456 edata
.cmd
= ARM_EXIDX_CMD_REG_POP
;
457 edata
.data
= ((op
& 0xf) << 8) | op2
;
458 edata
.data
= edata
.data
<< 4;
461 else if ((op
& 0xf0) == 0x90) {
462 if (op
== 0x9d || op
== 0x9f) {
463 // 9d: Reserved as prefix for ARM register to register moves
464 // 9f: Reserved as prefix for Intel Wireless MMX reg to reg moves
465 edata
.cmd
= ARM_EXIDX_CMD_RESERVED
;
468 edata
.cmd
= ARM_EXIDX_CMD_REG_TO_SP
;
469 edata
.data
= op
& 0x0f;
472 else if ((op
& 0xf0) == 0xa0) {
473 // Pop r4 to r[4+nnn], or
474 // Pop r4 to r[4+nnn] and r14
475 Int nnn
= (op
& 0x07);
476 edata
.data
= (1 << (nnn
+ 1)) - 1;
477 edata
.data
= edata
.data
<< 4;
478 if (op
& 0x08) edata
.data
|= 1 << 14;
479 edata
.cmd
= ARM_EXIDX_CMD_REG_POP
;
481 else if (op
== ARM_EXTBL_OP_FINISH
) {
483 edata
.cmd
= ARM_EXIDX_CMD_FINISH
;
486 else if (op
== 0xb1) {
489 if (op2
== 0 || (op2
& 0xf0)) {
491 edata
.cmd
= ARM_EXIDX_CMD_RESERVED
;
493 // Pop integer registers under mask {r3,r2,r1,r0}
494 edata
.cmd
= ARM_EXIDX_CMD_REG_POP
;
495 edata
.data
= op2
& 0x0f;
498 else if (op
== 0xb2) {
499 // vsp = vsp + 0x204 + (uleb128 << 2)
501 UChar byte
, shift
= 0;
504 offset
|= (byte
& 0x7f) << shift
;
506 } while ((byte
& 0x80) && buf
< end
);
507 edata
.data
= offset
* 4 + 0x204;
508 edata
.cmd
= ARM_EXIDX_CMD_ADD_TO_VSP
;
510 else if (op
== 0xb3 || op
== 0xc8 || op
== 0xc9) {
511 // b3: Pop VFP regs D[ssss] to D[ssss+cccc], FSTMFDX-ishly
512 // c8: Pop VFP regs D[16+ssss] to D[16+ssss+cccc], FSTMFDD-ishly
513 // c9: Pop VFP regs D[ssss] to D[ssss+cccc], FSTMFDD-ishly
514 edata
.cmd
= ARM_EXIDX_CMD_VFP_POP
;
515 GET_BUF_U8(edata
.data
);
516 if (op
== 0xc8) edata
.data
|= ARM_EXIDX_VFP_SHIFT_16
;
517 if (op
!= 0xb3) edata
.data
|= ARM_EXIDX_VFP_FSTMD
;
519 else if ((op
& 0xf8) == 0xb8 || (op
& 0xf8) == 0xd0) {
520 // b8: Pop VFP regs D[8] to D[8+nnn], FSTMFDX-ishly
521 // d0: Pop VFP regs D[8] to D[8+nnn], FSTMFDD-ishly
522 edata
.cmd
= ARM_EXIDX_CMD_VFP_POP
;
523 edata
.data
= 0x80 | (op
& 0x07);
524 if ((op
& 0xf8) == 0xd0) edata
.data
|= ARM_EXIDX_VFP_FSTMD
;
526 else if (op
>= 0xc0 && op
<= 0xc5) {
527 // Intel Wireless MMX pop wR[10]-wr[10+nnn], nnn != 6,7
528 edata
.cmd
= ARM_EXIDX_CMD_WREG_POP
;
529 edata
.data
= 0xa0 | (op
& 0x07);
531 else if (op
== 0xc6) {
532 // Intel Wireless MMX pop wR[ssss] to wR[ssss+cccc]
533 edata
.cmd
= ARM_EXIDX_CMD_WREG_POP
;
534 GET_BUF_U8(edata
.data
);
536 else if (op
== 0xc7) {
539 if (op2
== 0 || (op2
& 0xf0)) {
541 edata
.cmd
= ARM_EXIDX_CMD_RESERVED
;
543 // Intel Wireless MMX pop wCGR registers under mask {wCGR3,2,1,0}
544 edata
.cmd
= ARM_EXIDX_CMD_WCGR_POP
;
545 edata
.data
= op2
& 0x0f;
550 edata
.cmd
= ARM_EXIDX_CMD_RESERVED
;
554 VG_(printf
)(" edata: cmd %08x data %08x\n",
555 (UInt
)edata
.cmd
, edata
.data
);
557 Int ret
= TranslateCmd ( state
, &edata
);
558 if (ret
< 0) return ret
;
566 /*------------------------------------------------------------*/
567 /*--- (Pass 3 of 3) The EXIDX summariser ---*/
568 /*------------------------------------------------------------*/
570 /* In this translation into DiCfSI_m, we're going to have the CFA play
571 the role of the VSP. That means that the VSP can be exactly any of
572 the CFA expressions, viz: {r7,r11,r12,r13) +/- offset.
574 All of this would be a lot simpler if the DiCfSI_m representation
575 was just a bit more expressive and orthogonal. But it isn't.
577 The central difficulty is that, although we can track changes
578 to the offset of VSP (via vsp_off), we can't deal with assignments
579 of an entirely new expression to it, because the existing
580 rules in |cfi| will almost certainly refer to the CFA, and so
581 changing it will make them invalid. Hence, below:
583 * for the case ARM_EXIDX_CMD_REG_TO_SP we simply disallow
584 assignment, and hence give up, if any rule refers to CFA
586 * for the case ARM_EXIDX_CMD_REG_POP, the SP (hence, VSP) is
587 updated by the pop, give up.
589 This is an ugly hack to work around not having a better (LUL-like)
590 expression representation. That said, these restrictions don't
591 appear to be a big problem in practice.
595 // The DiCfSI_m under construction
598 // For generating CFI register expressions, if needed.
603 /* Generate a trivial CfiExpr, for the ARM(32) integer register
604 numbered |gprNo|. First ensure this DebugInfo has a cfsi_expr
605 array in which to park it. Returns -1 if |gprNo| cannot be
606 represented, otherwise returns a value >= 0. */
608 Int
gen_CfiExpr_CfiReg_ARM_GPR ( /*MB_MOD*/DebugInfo
* di
, UInt gprNo
)
610 CfiReg creg
= Creg_INVALID
;
612 case 13: creg
= Creg_ARM_R13
; break;
613 case 12: creg
= Creg_ARM_R12
; break;
614 case 15: creg
= Creg_ARM_R15
; break;
615 case 14: creg
= Creg_ARM_R14
; break;
616 case 7: creg
= Creg_ARM_R7
; break;
619 if (creg
== Creg_INVALID
) {
622 if (!di
->cfsi_exprs
) {
623 di
->cfsi_exprs
= VG_(newXA
)( ML_(dinfo_zalloc
), "di.gCCAG",
624 ML_(dinfo_free
), sizeof(CfiExpr
) );
626 Int res
= ML_(CfiExpr_CfiReg
)( di
->cfsi_exprs
, creg
);
632 /* Given a DiCfSI_m, find the _how/_off pair for the given ARM(32) GPR
633 number inside |cfsi_m|, or return NULL for both if that register
634 number is not represented. */
636 void maybeFindExprForRegno( /*OUT*/UChar
** howPP
, /*OUT*/Int
** offPP
,
637 DiCfSI_m
* cfsi_m
, Int regNo
)
640 case 15: *howPP
= &cfsi_m
->ra_how
; *offPP
= &cfsi_m
->ra_off
; return;
641 case 14: *howPP
= &cfsi_m
->r14_how
; *offPP
= &cfsi_m
->r14_off
; return;
642 case 13: *howPP
= &cfsi_m
->r13_how
; *offPP
= &cfsi_m
->r13_off
; return;
643 case 12: *howPP
= &cfsi_m
->r12_how
; *offPP
= &cfsi_m
->r12_off
; return;
644 case 11: *howPP
= &cfsi_m
->r11_how
; *offPP
= &cfsi_m
->r11_off
; return;
645 case 7: *howPP
= &cfsi_m
->r7_how
; *offPP
= &cfsi_m
->r7_off
; return;
648 *howPP
= NULL
; *offPP
= NULL
;
652 /* Set cfi.cfa_{how,off} so as to be a copy of the expression denoted
653 by (how,off), if it is possible to do so. Returns True on
656 Bool
setCFAfromCFIR( /*MOD*/DiCfSI_m
* cfi
, XArray*/
*CfiExpr*/ cfsi_exprs
,
661 if (!cfsi_exprs
) return False
;
662 CfiExpr
* e
= (CfiExpr
*)VG_(indexXA
)(cfsi_exprs
, off
);
663 if (e
->tag
!= Cex_CfiReg
) return False
;
664 if (e
->Cex
.CfiReg
.reg
== Creg_ARM_R7
) {
665 cfi
->cfa_how
= CFIC_ARM_R7REL
;
669 ML_(ppCfiExpr
)(cfsi_exprs
, off
);
674 VG_(printf
)("setCFAfromCFIR: FAIL: how %d off %d\n", how
, off
);
680 #define ARM_EXBUF_START(x) (((x) >> 4) & 0x0f)
681 #define ARM_EXBUF_COUNT(x) ((x) & 0x0f)
682 #define ARM_EXBUF_END(x) (ARM_EXBUF_START(x) + ARM_EXBUF_COUNT(x))
685 static Bool
mentionsCFA ( DiCfSI_m
* cfi
)
687 # define MENTIONS_CFA(_how) ((_how) == CFIR_CFAREL || (_how) == CFIR_MEMCFAREL)
688 if (MENTIONS_CFA(cfi
->ra_how
)) return True
;
689 if (MENTIONS_CFA(cfi
->r14_how
)) return True
;
690 if (MENTIONS_CFA(cfi
->r13_how
)) return True
;
691 if (MENTIONS_CFA(cfi
->r12_how
)) return True
;
692 if (MENTIONS_CFA(cfi
->r11_how
)) return True
;
693 if (MENTIONS_CFA(cfi
->r7_how
)) return True
;
699 // Translate command from extab_data to command for Module.
701 Int
TranslateCmd(/*MOD*/SummState
* state
, const ExtabData
* edata
)
703 /* Stay sane: check that the CFA has the expected form. */
705 switch (state
->cfi
.cfa_how
) {
706 case CFIC_ARM_R13REL
: case CFIC_ARM_R12REL
:
707 case CFIC_ARM_R11REL
: case CFIC_ARM_R7REL
: break;
708 default: vg_assert(0);
712 VG_(printf
)(" TranslateCmd: ");
718 switch (edata
->cmd
) {
719 case ARM_EXIDX_CMD_FINISH
:
720 /* Copy LR to PC if there isn't currently a rule for PC in force. */
721 if (state
->cfi
.ra_how
== CFIR_UNKNOWN
) {
722 if (state
->cfi
.r14_how
== CFIR_UNKNOWN
) {
723 state
->cfi
.ra_how
= CFIR_EXPR
;
724 state
->cfi
.ra_off
= gen_CfiExpr_CfiReg_ARM_GPR(state
->di
, 14);
725 vg_assert(state
->cfi
.ra_off
>= 0);
727 state
->cfi
.ra_how
= state
->cfi
.r14_how
;
728 state
->cfi
.ra_off
= state
->cfi
.r14_off
;
732 case ARM_EXIDX_CMD_SUB_FROM_VSP
:
733 state
->vsp_off
-= (Int
)(edata
->data
);
735 case ARM_EXIDX_CMD_ADD_TO_VSP
:
736 state
->vsp_off
+= (Int
)(edata
->data
);
738 case ARM_EXIDX_CMD_REG_POP
: {
740 for (i
= 0; i
< 16; i
++) {
741 if (edata
->data
& (1 << i
)) {
742 // See if we're summarising for int register |i|. If so,
743 // describe how to pull it off the stack. The cast of |i| is
744 // a bit of a kludge but works because DW_REG_ARM_Rn has the
745 // value |n|, for 0 <= |n| <= 15 -- that is, for the ARM
746 // general-purpose registers.
747 UChar
* rX_howP
= NULL
;
749 maybeFindExprForRegno(&rX_howP
, &rX_offP
, &state
->cfi
, i
);
752 /* rX_howP and rX_offP point at one of the rX fields
753 in |state->cfi|. Hence the following assignments
754 are really updating |state->cfi|. */
755 *rX_howP
= CFIR_MEMCFAREL
;
756 *rX_offP
= state
->vsp_off
;
758 /* We're not tracking this register, so ignore it. */
764 /* Set cfa in case the SP got popped. */
765 if (edata
->data
& (1 << 13)) {
766 // vsp = curr_rules_.mR13expr;
767 //state->cfi.cfa_how =
768 //state->cfi.cfa_off =
769 //state->vsp_off = 0;
770 // If this happens, it would make the existing CFA references
771 // in the summary invalid. So give up instead.
776 case ARM_EXIDX_CMD_REG_TO_SP
: {
777 /* We're generating a new value for the CFA/VSP here. Hence,
778 if the summary already refers to the CFA at all, we can't
779 go any further, and have to abandon summarisation. */
780 if (mentionsCFA(&state
->cfi
))
782 vg_assert(edata
->data
< 16);
783 Int reg_no
= edata
->data
;
784 // Same comment as above, re the casting of |reg_no|, applies.
785 UChar
* rX_howP
= NULL
;
787 maybeFindExprForRegno(&rX_howP
, &rX_offP
, &state
->cfi
, reg_no
);
790 if (*rX_howP
== CFIR_UNKNOWN
) {
791 //curr_rules_.mR13expr = LExpr(LExpr::NODEREF, reg_no, 0);
792 Int expr_ix
= gen_CfiExpr_CfiReg_ARM_GPR(state
->di
, reg_no
);
794 state
->cfi
.r13_how
= CFIR_EXPR
;
795 state
->cfi
.r13_off
= expr_ix
;
800 //curr_rules_.mR13expr = *reg_exprP;
801 state
->cfi
.r13_how
= *rX_howP
;
802 state
->cfi
.r13_off
= *rX_offP
;
804 //vsp = curr_rules_.mR13expr;
805 Bool ok
= setCFAfromCFIR( &state
->cfi
, state
->di
->cfsi_exprs
,
806 state
->cfi
.r13_how
, state
->cfi
.r13_off
);
807 if (!ok
) goto cant_summarise
;
814 case ARM_EXIDX_CMD_VFP_POP
: {
815 /* Don't recover VFP registers, but be sure to adjust the stack
818 for (i
= ARM_EXBUF_START(edata
->data
);
819 i
<= ARM_EXBUF_END(edata
->data
); i
++) {
822 if (!(edata
->data
& ARM_EXIDX_VFP_FSTMD
)) {
827 case ARM_EXIDX_CMD_WREG_POP
: {
829 for (i
= ARM_EXBUF_START(edata
->data
);
830 i
<= ARM_EXBUF_END(edata
->data
); i
++) {
835 case ARM_EXIDX_CMD_WCGR_POP
: {
837 // Pop wCGR registers under mask {wCGR3,2,1,0}, hence "i < 4"
838 for (i
= 0; i
< 4; i
++) {
839 if (edata
->data
& (1 << i
)) {
845 case ARM_EXIDX_CMD_REFUSED
:
846 case ARM_EXIDX_CMD_RESERVED
:
857 /* Initialise the EXIDX summariser, by writing initial values in |state|. */
859 void AddStackFrame ( /*OUT*/SummState
* state
,
862 VG_(bzero_inline
)(state
, sizeof(*state
));
865 /* Initialise the DiCfSI_m that we are building. */
866 state
->cfi
.cfa_how
= CFIC_ARM_R13REL
;
867 state
->cfi
.cfa_off
= 0;
868 state
->cfi
.ra_how
= CFIR_UNKNOWN
;
869 state
->cfi
.r14_how
= CFIR_UNKNOWN
;
870 state
->cfi
.r13_how
= CFIR_UNKNOWN
;
871 state
->cfi
.r12_how
= CFIR_UNKNOWN
;
872 state
->cfi
.r11_how
= CFIR_UNKNOWN
;
873 state
->cfi
.r7_how
= CFIR_UNKNOWN
;
877 void SubmitStackFrame( /*MOD*/DebugInfo
* di
,
878 SummState
* state
, Addr avma
, SizeT len
)
880 // JRS: I'm really not sure what this means, or if it is necessary
881 // return address always winds up in pc
882 //stack_frame_entry_->initial_rules[ustr__ZDra()] // ".ra"
883 // = stack_frame_entry_->initial_rules[ustr__pc()];
884 // maybe don't need to do anything here?
886 // the final value of vsp is the new value of sp.
887 switch (state
->cfi
.cfa_how
) {
888 case CFIC_ARM_R13REL
: case CFIC_ARM_R12REL
:
889 case CFIC_ARM_R11REL
: case CFIC_ARM_R7REL
: break;
890 default: vg_assert(0);
892 state
->cfi
.r13_how
= CFIR_CFAREL
;
893 state
->cfi
.r13_off
= state
->vsp_off
;
895 // Finally, add the completed RuleSet to the SecMap
898 // Futz with the rules for r4 .. r11 in the same way as happens
899 // with the CFI summariser:
900 /* Mark callee-saved registers (r4 .. r11) as unchanged, if there is
901 no other information about them. FIXME: do this just once, at
902 the point where the ruleset is committed. */
903 if (state
->cfi
.r7_how
== CFIR_UNKNOWN
) {
904 state
->cfi
.r7_how
= CFIR_SAME
;
905 state
->cfi
.r7_off
= 0;
907 if (state
->cfi
.r11_how
== CFIR_UNKNOWN
) {
908 state
->cfi
.r11_how
= CFIR_SAME
;
909 state
->cfi
.r11_off
= 0;
911 if (state
->cfi
.r12_how
== CFIR_UNKNOWN
) {
912 state
->cfi
.r12_how
= CFIR_SAME
;
913 state
->cfi
.r12_off
= 0;
915 if (state
->cfi
.r14_how
== CFIR_UNKNOWN
) {
916 state
->cfi
.r14_how
= CFIR_SAME
;
917 state
->cfi
.r14_off
= 0;
921 ML_(addDiCfSI
)(di
, avma
, len
, &state
->cfi
);
923 ML_(ppDiCfSI
)(di
->cfsi_exprs
, avma
, len
, &state
->cfi
);
928 /*------------------------------------------------------------*/
929 /*--- Top level ---*/
930 /*------------------------------------------------------------*/
932 void ML_(read_exidx
) ( /*MOD*/DebugInfo
* di
,
933 UChar
* exidx_img
, SizeT exidx_size
,
934 UChar
* extab_img
, SizeT extab_size
,
939 VG_(printf
)("BEGIN ML_(read_exidx) exidx_img=[%p, +%lu) "
940 "extab_img=[%p, +%lu) text_last_svma=%lx text_bias=%lx\n",
941 exidx_img
, exidx_size
, extab_img
, extab_size
,
942 text_last_svma
, (UWord
)text_bias
);
944 MemoryRange mr_exidx
, mr_extab
;
945 ok
= MemoryRange__init(&mr_exidx
, exidx_img
, exidx_size
);
946 ok
= ok
&& MemoryRange__init(&mr_extab
, extab_img
, extab_size
);
948 complain(".exidx or .extab image area wraparound");
952 const ExidxEntry
* start_img
= (const ExidxEntry
*)exidx_img
;
953 const ExidxEntry
* end_img
= (const ExidxEntry
*)(exidx_img
+ exidx_size
);
955 if (VG_(clo_verbosity
) > 1)
956 VG_(message
)(Vg_DebugMsg
, " Reading EXIDX entries: %lu available\n",
957 exidx_size
/ sizeof(ExidxEntry
) );
959 // Iterate over each of the EXIDX entries (pairs of 32-bit words).
960 // These occupy the entire .exidx section.
961 UWord n_attempted
= 0, n_successful
= 0;
963 const ExidxEntry
* entry_img
;
964 for (entry_img
= start_img
; entry_img
< end_img
; ++entry_img
) {
967 // Figure out the code address range that this table entry_img is
969 Addr avma
= (Addr
)Prel31ToAddr(&entry_img
->addr
);
971 VG_(printf
)("XXX1 entry: entry->addr 0x%x, avma 0x%lx\n",
972 entry_img
->addr
, avma
);
975 if (entry_img
< end_img
- 1) {
976 next_avma
= (Addr
)Prel31ToAddr(&(entry_img
+1)->addr
);
978 // This is the last EXIDX entry in the sequence, so we don't
979 // have an address for the start of the next function, to limit
980 // this one. Instead use the address of the last byte of the
981 // text section associated with this .exidx section, that we
982 // have been given. So as to avoid junking up the CFI unwind
983 // tables with absurdly large address ranges in the case where
984 // text_last_svma_ is wrong, only use the value if it is nonzero
985 // and within one page of |svma|. Otherwise assume a length of 1.
987 // In some cases, gcc has been observed to finish the exidx
988 // section with an entry of length 1 marked CANT_UNWIND,
989 // presumably exactly for the purpose of giving a definite
990 // length for the last real entry, without having to look at
991 // text segment boundaries.
992 Addr text_last_avma
= text_last_svma
+ text_bias
;
995 Addr maybe_next_avma
= text_last_avma
+ 1;
996 if (maybe_next_avma
> avma
&& maybe_next_avma
- avma
<= 4096) {
997 next_avma
= maybe_next_avma
;
1000 next_avma
= avma
+ 1;
1004 if (!plausible
&& avma
!= text_last_avma
+ 1) {
1006 VG_(snprintf
)(buf
, sizeof(buf
),
1007 "Implausible EXIDX last entry size %lu"
1008 "; using 1 instead.", text_last_avma
- avma
);
1009 buf
[sizeof(buf
)-1] = 0;
1014 // Extract the unwind info into |buf|. This might fail for
1015 // various reasons. It involves reading both the .exidx and
1016 // .extab sections. All accesses to those sections are
1019 VG_(printf
)("XXX1 entry is for AVMA 0x%lx 0x%lx\n",
1021 UChar buf
[ARM_EXIDX_TABLE_LIMIT
];
1024 = ExtabEntryExtract(&mr_exidx
, &mr_extab
,
1025 entry_img
, buf
, sizeof(buf
), &buf_used
);
1026 if (res
!= ExSuccess
) {
1027 // Couldn't extract the unwind info, for some reason. Move on.
1029 case ExInBufOverflow
:
1030 complain("ExtabEntryExtract: .exidx/.extab section overrun");
1032 case ExOutBufOverflow
:
1033 complain("ExtabEntryExtract: bytecode buffer overflow");
1036 // Some functions are marked CantUnwind by the compiler.
1037 // Don't record these as attempted, since that's just
1038 // confusing, and failure to summarise them is not the fault
1042 complain("ExtabEntryExtract: function is marked CANT_UNWIND");
1044 case ExCantRepresent
:
1045 complain("ExtabEntryExtract: bytecode can't be represented");
1048 complain("ExtabEntryExtract: index table entry is invalid");
1052 VG_(snprintf
)(mbuf
, sizeof(mbuf
),
1053 "ExtabEntryExtract: unknown error: %d", (Int
)res
);
1054 buf
[sizeof(mbuf
)-1] = 0;
1062 // Finally, work through the unwind instructions in |buf| and
1063 // create CFI entries that Valgrind can use. This can also fail.
1064 // First, initialise the summariser's running state, into which
1065 // ExtabEntryDecode will write the CFI entries.
1068 AddStackFrame( &state
, di
);
1069 Int ret
= ExtabEntryDecode( &state
, buf
, buf_used
);
1071 /* Failed summarisation. Ignore and move on. */
1073 VG_(snprintf
)(mbuf
, sizeof(mbuf
),
1074 "ExtabEntryDecode: failed with error code: %d", ret
);
1075 mbuf
[sizeof(mbuf
)-1] = 0;
1078 /* Successful summarisation. Add it to the collection. */
1079 SubmitStackFrame( di
, &state
, avma
, next_avma
- avma
);
1083 } /* iterating over .exidx */
1085 if (VG_(clo_verbosity
) > 1)
1086 VG_(message
)(Vg_DebugMsg
,
1087 " Reading EXIDX entries: %lu attempted, %lu successful\n",
1088 n_attempted
, n_successful
);
1091 #endif /* defined(VGA_arm) */
1093 /*--------------------------------------------------------------------*/
1094 /*--- end readexidx.c ---*/
1095 /*--------------------------------------------------------------------*/