drd/tests/tsan_unittest: Avoid that this test reads from uninitialized memory
[valgrind.git] / coregrind / m_debuginfo / readexidx.c
blobe79dc6f5bb3324688552e4970c8f01d5253d18e3
1 /* -*- mode: C; c-basic-offset: 3; -*- */
3 /*--------------------------------------------------------------------*/
4 /*--- Reading of ARM(32) EXIDX unwind information readexidx.c ---*/
5 /*--------------------------------------------------------------------*/
7 /*
8 This file is part of Valgrind, a dynamic binary instrumentation
9 framework.
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, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26 02111-1307, USA.
28 The GNU General Public License is contained in the file COPYING.
31 /* libunwind - a platform-independent unwind library
32 Copyright 2011 Linaro Limited
34 This file is part of libunwind.
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:
44 The above copyright notice and this permission notice shall be
45 included in all copies or substantial portions of the Software.
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. */
56 // Copyright (c) 2010 Google Inc.
57 // All rights reserved.
59 // Redistribution and use in source and binary forms, with or without
60 // modification, are permitted provided that the following conditions are
61 // met:
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.
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.
86 // Derived originally from libunwind, with very extensive modifications.
87 /* Contributed by Julian Seward <jseward@acm.org> */
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.
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
97 // EXIDX data is presented in two parts:
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.
105 // * an area containing the unwind bytecodes.
107 // General flow is: ML_(read_exidx) iterates over all
108 // of the index table entries (pairs). For each entry, it:
110 // * calls ExtabEntryExtract to copy the bytecode out into
111 // an intermediate buffer.
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 ..
117 // * .. TranslateCmd, which generates the pseudo-CFI
118 // records that Valgrind stores.
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
126 #if defined(VGA_arm)
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"
134 #include "priv_storage.h"
135 #include "priv_readexidx.h"
138 static void complain ( const HChar* str )
140 if (!VG_(clo_xml) && VG_(clo_verbosity) > 1)
141 VG_(message)(Vg_UserMsg,
142 " Warning: whilst reading EXIDX: %s\n", str);
146 /*------------------------------------------------------------*/
147 /*--- MemoryRange ---*/
148 /*------------------------------------------------------------*/
150 typedef struct { Addr start; SizeT len; } MemoryRange;
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 )
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;
163 mr->start = start;
164 mr->len = len;
165 return True;
168 static Bool MemoryRange__covers ( MemoryRange* mr,
169 const void* startV, SizeT len )
171 vg_assert(len > 0);
172 if (mr->len == 0) {
173 return False;
175 Addr start = (Addr)startV;
176 return start >= mr->start && start + len - 1 <= mr->start + mr->len - 1;
180 /*------------------------------------------------------------*/
181 /*--- (Pass 1 of 3) The EXIDX extractor ---*/
182 /*------------------------------------------------------------*/
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)
189 /* These are in the ARM-defined format, so their layout is important. */
190 typedef
191 struct { UInt addr; UInt data; }
192 ExidxEntry;
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
204 ExExtractResult;
207 /* Helper function for fishing bits out of the EXIDX representation. */
208 static const void* Prel31ToAddr(const void* addr)
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 ((const UChar*)addr) + (UWord)offset64;
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)
232 Bool ok;
233 MemoryRange mr_out;
234 ok = MemoryRange__init(&mr_out, buf, buf_size);
235 if (!ok) return ExOutBufOverflow;
237 *buf_used = 0;
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)
244 # define GET_EX_U32(_lval, _addr, _mr) \
245 do { if (!MemoryRange__covers((_mr), (const void*)(_addr), 4)) \
246 return ExInBufOverflow; \
247 (_lval) = *(const UInt*)(_addr); } while (0)
249 # define GET_EXIDX_U32(_lval, _addr) \
250 GET_EX_U32(_lval, _addr, mr_exidx)
252 # define GET_EXTAB_U32(_lval, _addr) \
253 GET_EX_U32(_lval, _addr, mr_extab)
255 UInt data;
256 GET_EXIDX_U32(data, &entry->data);
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;
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 const UInt* extbl_data; // the handler entry, if not inlined
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;
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 = 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 arbitrary machine code, which is something we
291 // can't represent here; hence reject it.
292 return ExCantRepresent;
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++;
302 // Now look at the handler table entry. The first word is |data|
303 // and subsequent words start at |*extbl_data|. The number of
304 // 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);
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);
329 else {
330 // The entry is invalid.
331 return ExInvalid;
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);
338 return ExSuccess;
340 # undef GET_EXTAB_U32
341 # undef GET_EXIDX_U32
342 # undef GET_U32
343 # undef PUT_BUF_U8
347 /*------------------------------------------------------------*/
348 /*--- (Pass 2 of 3) The EXIDX decoder ---*/
349 /*------------------------------------------------------------*/
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
367 ExtabCmd;
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 "???";
386 typedef
387 struct { ExtabCmd cmd; UInt data; }
388 ExtabData;
390 static void ppExtabData ( const ExtabData* etd ) {
391 VG_(printf)("ExtabData{%-12s 0x%08x}", showExtabCmd(etd->cmd), etd->data);
395 enum extab_cmd_flags {
396 ARM_EXIDX_VFP_SHIFT_16 = 1 << 16,
397 ARM_EXIDX_VFP_FSTMD = 1 << 17, // distinguishes FSTMxxD from FSTMxxX
401 /* Forwards */
402 typedef struct _SummState SummState;
403 static Int TranslateCmd(/*MOD*/SummState* state, const ExtabData* edata);
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.
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)
419 if (buf == NULL || buf_size == 0)
420 return -3;
422 MemoryRange mr_in;
423 Bool ok = MemoryRange__init(&mr_in, buf, buf_size);
424 if (!ok)
425 return -2;
427 # define GET_BUF_U8(_lval) \
428 do { if (!MemoryRange__covers(&mr_in, buf, 1)) \
429 return -4; \
430 (_lval) = *(buf++); } while (0)
432 const UChar* end = buf + buf_size;
434 while (buf < end) {
435 ExtabData edata;
436 VG_(bzero_inline)(&edata, sizeof(edata));
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;
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;
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;
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;
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;
483 else if (op == ARM_EXTBL_OP_FINISH) {
484 // Finish
485 edata.cmd = ARM_EXIDX_CMD_FINISH;
486 buf = end;
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;
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;
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;
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;
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);
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);
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;
550 else {
551 // Spare
552 edata.cmd = ARM_EXIDX_CMD_RESERVED;
555 if (0)
556 VG_(printf)(" edata: cmd %08x data %08x\n",
557 (UInt)edata.cmd, edata.data);
559 Int ret = TranslateCmd ( state, &edata );
560 if (ret < 0) return ret;
562 return 0;
564 # undef GET_BUF_U8
568 /*------------------------------------------------------------*/
569 /*--- (Pass 3 of 3) The EXIDX summariser ---*/
570 /*------------------------------------------------------------*/
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.
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.
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:
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
588 * for the case ARM_EXIDX_CMD_REG_POP, the SP (hence, VSP) is
589 updated by the pop, give up.
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.
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;
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 )
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;
621 if (creg == Creg_INVALID) {
622 return -1;
624 if (!di->cfsi_exprs) {
625 di->cfsi_exprs = VG_(newXA)( ML_(dinfo_zalloc), "di.gCCAG",
626 ML_(dinfo_free), sizeof(CfiExpr) );
628 Int res = ML_(CfiExpr_CfiReg)( di->cfsi_exprs, creg );
629 vg_assert(res >= 0);
630 return res;
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 )
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;
650 *howPP = NULL; *offPP = NULL;
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 )
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;
671 ML_(ppCfiExpr)(cfsi_exprs, off);
672 vg_assert(0);
673 default:
674 break;
676 VG_(printf)("setCFAfromCFIR: FAIL: how %d off %d\n", how, off);
677 vg_assert(0);
678 return False;
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))
687 static Bool mentionsCFA ( DiCfSI_m* cfi )
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
701 // Translate command from extab_data to command for Module.
702 static
703 Int TranslateCmd(/*MOD*/SummState* state, const ExtabData* edata)
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);
713 if (0) {
714 VG_(printf)(" TranslateCmd: ");
715 ppExtabData(edata);
716 VG_(printf)("\n");
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;
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);
763 state->vsp_off += 4;
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;
776 break;
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;
801 } else {
802 //curr_rules_.mR13expr = *reg_exprP;
803 state->cfi.r13_how = *rX_howP;
804 state->cfi.r13_off = *rX_offP;
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);
814 break;
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;
824 if (!(edata->data & ARM_EXIDX_VFP_FSTMD)) {
825 state->vsp_off += 4;
827 break;
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;
835 break;
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;
845 break;
847 case ARM_EXIDX_CMD_REFUSED:
848 case ARM_EXIDX_CMD_RESERVED:
849 ret = -1;
850 break;
852 return ret;
854 cant_summarise:
855 return -10;
859 /* Initialise the EXIDX summariser, by writing initial values in |state|. */
860 static
861 void AddStackFrame ( /*OUT*/SummState* state,
862 DebugInfo* di )
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;
878 static
879 void SubmitStackFrame( /*MOD*/DebugInfo* di,
880 SummState* state, Addr avma, SizeT len )
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?
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);
894 state->cfi.r13_how = CFIR_CFAREL;
895 state->cfi.r13_off = state->vsp_off;
897 // Finally, add the completed RuleSet to the SecMap
898 if (len > 0) {
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;
909 if (state->cfi.r11_how == CFIR_UNKNOWN) {
910 state->cfi.r11_how = CFIR_SAME;
911 state->cfi.r11_off = 0;
913 if (state->cfi.r12_how == CFIR_UNKNOWN) {
914 state->cfi.r12_how = CFIR_SAME;
915 state->cfi.r12_off = 0;
917 if (state->cfi.r14_how == CFIR_UNKNOWN) {
918 state->cfi.r14_how = CFIR_SAME;
919 state->cfi.r14_off = 0;
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);
930 /*------------------------------------------------------------*/
931 /*--- Top level ---*/
932 /*------------------------------------------------------------*/
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 )
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, (UWord)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;
954 const ExidxEntry* start_img = (const ExidxEntry*)exidx_img;
955 const ExidxEntry* end_img = (const ExidxEntry*)(exidx_img + exidx_size);
957 if (VG_(clo_verbosity) > 1)
958 VG_(message)(Vg_DebugMsg, " Reading EXIDX entries: %lu available\n",
959 exidx_size / sizeof(ExidxEntry) );
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;
965 const ExidxEntry* entry_img;
966 for (entry_img = start_img; entry_img < end_img; ++entry_img) {
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%x, avma 0x%lx\n",
974 entry_img->addr, avma);
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.
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;
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;
1006 if (!plausible && avma != text_last_avma + 1) {
1007 HChar buf[100];
1008 VG_(snprintf)(buf, sizeof(buf),
1009 "Implausible EXIDX last entry size %lu"
1010 "; using 1 instead.", text_last_avma - avma);
1011 buf[sizeof(buf)-1] = 0;
1012 complain(buf);
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;
1061 continue;
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.
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++;
1085 } /* iterating over .exidx */
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);
1093 #endif /* defined(VGA_arm) */
1095 /*--------------------------------------------------------------------*/
1096 /*--- end readexidx.c ---*/
1097 /*--------------------------------------------------------------------*/