Print this page
5688 ELF tools need to be more careful with dwarf data
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/sgs/elfdump/common/dwarf.c
+++ new/usr/src/cmd/sgs/elfdump/common/dwarf.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 27 #include <_libelf.h>
28 28 #include <dwarf.h>
29 29 #include <stdio.h>
30 30 #include <unistd.h>
31 31 #include <errno.h>
32 32 #include <strings.h>
↓ open down ↓ |
32 lines elided |
↑ open up ↑ |
33 33 #include <debug.h>
34 34 #include <conv.h>
35 35 #include <msg.h>
36 36 #include <_elfdump.h>
37 37
38 38
39 39 /*
40 40 * Data from eh_frame section used by dump_cfi()
41 41 */
42 42 typedef struct {
43 + const char *file;
44 + const char *sh_name;
43 45 Half e_machine; /* ehdr->e_machine */
44 46 uchar_t *e_ident; /* ehdr->e_ident */
45 47 uint64_t sh_addr; /* Address of eh_frame section */
46 48 int do_swap; /* True if object and system byte */
47 49 /* order differs */
48 50 int cieRflag; /* R flag from current CIE */
49 51 uint64_t ciecalign; /* CIE code align factor */
50 52 int64_t ciedalign; /* CIE data align factor */
51 53 uint64_t fdeinitloc; /* FDE initial location */
52 54 uint64_t gotaddr; /* Address of the GOT */
53 55 } dump_cfi_state_t;
54 56
55 57
56 58 /*
57 59 * Extract an unsigned integer value from an .eh_frame section, converting it
58 60 * from its native byte order to that of the running machine if necessary.
59 61 *
60 62 * entry:
61 63 * data - Base address from which to extract datum
62 64 * ndx - Address of variable giving index to start byte in data.
↓ open down ↓ |
10 lines elided |
↑ open up ↑ |
63 65 * size - # of bytes in datum. Must be one of: 1, 2, 4, 8
64 66 * do_swap - True if the data is in a different byte order than that
65 67 * of the host system.
66 68 *
67 69 * exit:
68 70 * *ndx is incremented by the size of the extracted datum.
69 71 *
70 72 * The requested datum is extracted, byte swapped if necessary,
71 73 * and returned.
72 74 */
73 -static uint64_t
74 -dwarf_extract_uint(uchar_t *data, uint64_t *ndx, int size, int do_swap)
75 +static dwarf_error_t
76 +dwarf_extract_uint(uchar_t *data, size_t len, uint64_t *ndx, int size,
77 + int do_swap, uint64_t *ret)
75 78 {
79 + if (((*ndx + size) > len) ||
80 + ((*ndx + size) < *ndx))
81 + return (DW_OVERFLOW);
82 +
76 83 switch (size) {
77 84 case 1:
78 - return (data[(*ndx)++]);
85 + *ret = (data[(*ndx)++]);
86 + return (DW_SUCCESS);
79 87 case 2:
80 88 {
81 89 Half r;
82 90 uchar_t *p = (uchar_t *)&r;
83 91
84 92 data += *ndx;
85 93 if (do_swap)
86 94 UL_ASSIGN_BSWAP_HALF(p, data);
87 95 else
88 96 UL_ASSIGN_HALF(p, data);
89 97
90 98 (*ndx) += 2;
91 - return (r);
99 + *ret = r;
100 + return (DW_SUCCESS);
92 101 }
93 102 case 4:
94 103 {
95 104 Word r;
96 105 uchar_t *p = (uchar_t *)&r;
97 106
98 107 data += *ndx;
99 108 if (do_swap)
100 109 UL_ASSIGN_BSWAP_WORD(p, data);
101 110 else
102 111 UL_ASSIGN_WORD(p, data);
103 112
104 113 (*ndx) += 4;
105 - return (r);
114 + *ret = r;
115 + return (DW_SUCCESS);
106 116 }
107 117
108 118 case 8:
109 119 {
110 120 uint64_t r;
111 121 uchar_t *p = (uchar_t *)&r;
112 122
113 123 data += *ndx;
114 124 if (do_swap)
115 125 UL_ASSIGN_BSWAP_LWORD(p, data);
116 126 else
117 127 UL_ASSIGN_LWORD(p, data);
118 128
119 129 (*ndx) += 8;
120 - return (r);
130 + *ret = r;
131 + return (DW_SUCCESS);
121 132 }
133 + default:
134 + return (DW_BAD_ENCODING);
122 135 }
123 136
124 - /* If here, an invalid size was specified */
125 - assert(0);
126 - return (0);
137 + /* NOTREACHED */
127 138 }
128 139
129 140 /*
130 141 * Map a DWARF register constant to the machine register name it
131 142 * corresponds to, formatting the result into buf.
132 143 *
133 144 * The assignment of DWARF register numbers is part of the system
134 145 * specific ABI for each platform.
135 146 *
136 147 * entry:
137 148 * regno - DWARF register number
138 149 * mach - ELF machine code for platform
139 150 * buf, bufsize - Buffer to receive the formatted result string
140 151 *
141 152 * exit:
142 153 * The results are formatted into buf, and buf is returned.
143 154 * If the generated output would exceed the size of the buffer
144 155 * provided, it will be clipped to fit.
145 156 */
146 157 static const char *
147 158 dwarf_regname(Half mach, int regno, char *buf, size_t bufsize)
148 159 {
149 160 Conv_inv_buf_t inv_buf;
150 161 const char *name;
151 162 int good_name;
152 163
153 164 name = conv_dwarf_regname(mach, regno, 0, &good_name, &inv_buf);
154 165
155 166 /*
156 167 * If there is a good mnemonic machine name for the register,
157 168 * format the result as 'r# (mnemonic)'. If there is no good
158 169 * name for it, then simply format the dwarf name as 'r#'.
159 170 */
160 171 if (good_name)
161 172 (void) snprintf(buf, bufsize, MSG_ORIG(MSG_REG_FMT_NAME),
162 173 regno, name);
163 174 else
164 175 (void) snprintf(buf, bufsize, MSG_ORIG(MSG_REG_FMT_BASIC),
165 176 regno);
166 177
167 178 return (buf);
168 179 }
↓ open down ↓ |
32 lines elided |
↑ open up ↑ |
169 180
170 181
171 182 /*
172 183 * Decode eh_frame Call Frame Instructions, printing each one on a
173 184 * separate line.
174 185 *
175 186 * entry:
176 187 * data - Address of base of eh_frame section being processed
177 188 * off - Offset of current FDE within eh_frame
178 189 * ndx - Index of current position within current FDE
179 - * len - Length of eh_frame section
190 + * len - Length of FDE
180 191 * state - Object, CIE, and FDE state for current request
181 192 * msg - Header message to issue before producing output.
182 193 * indent - # of indentation characters issued for each line of output.
183 194 *
184 195 * exit:
185 196 * The Call Frame Instructions have been decoded and printed.
186 197 *
187 198 * *ndx has been incremented to contain the index of the next
188 199 * byte of data to be processed in eh_frame.
189 200 *
190 201 * note:
191 202 * The format of Call Frame Instructions in .eh_frame sections is based
192 203 * on the DWARF specification.
193 204 */
194 205 static void
195 206 dump_cfi(uchar_t *data, uint64_t off, uint64_t *ndx, uint_t len,
196 207 dump_cfi_state_t *state, const char *msg, int indent)
197 208 {
198 209 /*
199 210 * We use %*s%s to insert leading whitespace and the op name.
200 211 * PREFIX supplies these arguments.
201 212 */
202 213 #define PREFIX indent, MSG_ORIG(MSG_STR_EMPTY), opname
203 214
204 215 /* Hide boilerplate clutter in calls to dwarf_regname() */
205 216 #define REGNAME(_rnum, _buf) \
206 217 dwarf_regname(state->e_machine, _rnum, _buf, sizeof (_buf))
207 218
208 219 /* Extract the lower 6 bits from an op code */
209 220 #define LOW_OP(_op) (_op & 0x3f)
210 221
211 222 char rbuf1[32], rbuf2[32];
212 223 Conv_inv_buf_t inv_buf;
213 224 uchar_t op;
214 225 const char *opname;
215 226 uint64_t oper1, oper2, cur_pc;
216 227 int64_t soper;
217 228 const char *loc_str;
218 229 int i;
219 230
220 231 dbg_print(0, msg);
221 232
222 233 /*
223 234 * In a CIE/FDE, the length field does not include it's own
224 235 * size. Hence, the value passed in is 4 less than the index
225 236 * of the actual final location.
226 237 */
227 238 len += 4;
228 239
229 240 /*
230 241 * There is a concept of the 'current location', which is the PC
231 242 * to which the current item applies. It starts out set to the
232 243 * FDE initial location, and can be set or incremented by
233 244 * various OP codes. cur_pc is used to track this.
234 245 *
235 246 * We want to use 'initloc' in the output the first time the location
236 247 * is referenced, and then switch to 'loc' for subsequent references.
237 248 * loc_str is used to manage that.
238 249 */
239 250 cur_pc = state->fdeinitloc;
240 251 loc_str = MSG_ORIG(MSG_STR_INITLOC);
241 252
242 253 while (*ndx < len) {
243 254 /*
244 255 * The first byte contains the primary op code in the top
245 256 * 2 bits, so there are 4 of them. Primary OP code
246 257 * 0 uses the lower 6 bits to specify a sub-opcode, allowing
247 258 * for 64 of them. The other 3 primary op codes use the
248 259 * lower 6 bits to hold an operand (a register #, or value).
249 260 *
250 261 * Check the primary OP code. If it's 1-3, handle it
251 262 * and move to the next loop iteration. For OP code 0,
252 263 * fall through to decode the sub-code.
253 264 */
254 265 op = data[off + (*ndx)++];
255 266 opname = conv_dwarf_cfa(op, 0, &inv_buf);
↓ open down ↓ |
66 lines elided |
↑ open up ↑ |
256 267 switch (op >> 6) {
257 268 case 0x1: /* v2: DW_CFA_advance_loc, delta */
258 269 oper1 = state->ciecalign * LOW_OP(op);
259 270 cur_pc += oper1;
260 271 dbg_print(0, MSG_ORIG(MSG_CFA_ADV_LOC), PREFIX,
261 272 loc_str, EC_XWORD(oper1), EC_XWORD(cur_pc));
262 273 loc_str = MSG_ORIG(MSG_STR_LOC);
263 274 continue;
264 275
265 276 case 0x2: /* v2: DW_CFA_offset, reg, offset */
266 - soper = uleb_extract(&data[off], ndx) *
267 - state->ciedalign;
277 + if (uleb_extract(&data[off], ndx, len, &oper1) ==
278 + DW_OVERFLOW) {
279 + (void) fprintf(stderr,
280 + MSG_INTL(MSG_ERR_DWOVRFLW),
281 + state->file, state->sh_name);
282 + return;
283 + }
284 +
285 + oper1 *= state->ciedalign;
268 286 dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX,
269 - REGNAME(LOW_OP(op), rbuf1), EC_SXWORD(soper));
287 + REGNAME(LOW_OP(op), rbuf1), EC_XWORD(oper1));
270 288 continue;
271 289
272 290 case 0x3: /* v2: DW_CFA_restore, reg */
273 291 dbg_print(0, MSG_ORIG(MSG_CFA_REG), PREFIX,
274 292 REGNAME(LOW_OP(op), rbuf1));
275 293 continue;
276 294 }
277 295
278 296 /*
279 297 * If we're here, the high order 2 bits are 0. The low 6 bits
280 298 * specify a sub-opcode defining the operation.
281 299 */
282 300 switch (op) {
283 301 case 0x00: /* v2: DW_CFA_nop */
284 302 /*
285 303 * No-ops are used to fill unused space required
286 304 * for alignment. It is common for there to be
287 305 * multiple adjacent nops. It saves space to report
288 306 * them all with a single line of output.
289 307 */
290 308 for (i = 1;
291 309 (*ndx < len) && (data[off + *ndx] == 0);
292 310 i++, (*ndx)++)
293 311 ;
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
294 312 dbg_print(0, MSG_ORIG(MSG_CFA_SIMPLEREP), PREFIX, i);
295 313 break;
296 314
297 315 case 0x0a: /* v2: DW_CFA_remember_state */
298 316 case 0x0b: /* v2: DW_CFA_restore_state */
299 317 case 0x2d: /* GNU: DW_CFA_GNU_window_save */
300 318 dbg_print(0, MSG_ORIG(MSG_CFA_SIMPLE), PREFIX);
301 319 break;
302 320
303 321 case 0x01: /* v2: DW_CFA_set_loc, address */
304 - cur_pc = dwarf_ehe_extract(&data[off], ndx,
305 - state->cieRflag, state->e_ident, B_FALSE,
306 - state->sh_addr, off + *ndx, state->gotaddr);
322 + switch (dwarf_ehe_extract(&data[off], len, ndx,
323 + &cur_pc, state->cieRflag, state->e_ident, B_FALSE,
324 + state->sh_addr, off + *ndx, state->gotaddr)) {
325 + case DW_OVERFLOW:
326 + (void) fprintf(stderr,
327 + MSG_INTL(MSG_ERR_DWOVRFLW),
328 + state->file, state->sh_name);
329 + return;
330 + case DW_BAD_ENCODING:
331 + (void) fprintf(stderr,
332 + MSG_INTL(MSG_ERR_DWBADENC),
333 + state->file, state->sh_name,
334 + state->cieRflag);
335 + return;
336 + case DW_SUCCESS:
337 + break;
338 + }
307 339 dbg_print(0, MSG_ORIG(MSG_CFA_CFASET), PREFIX,
308 340 EC_XWORD(cur_pc));
309 341 break;
310 342
311 343 case 0x02: /* v2: DW_CFA_advance_loc_1, 1-byte delta */
312 344 case 0x03: /* v2: DW_CFA_advance_loc_2, 2-byte delta */
313 345 case 0x04: /* v2: DW_CFA_advance_loc_4, 4-byte delta */
314 346 /*
315 347 * Since the codes are contiguous, and the sizes are
316 348 * powers of 2, we can compute the word width from
317 349 * the code.
318 350 */
319 351 i = 1 << (op - 0x02);
320 - oper1 = dwarf_extract_uint(data + off, ndx, i,
321 - state->do_swap) * state->ciecalign;
352 + switch (dwarf_extract_uint(data + off, len,
353 + ndx, i, state->do_swap, &oper1)) {
354 + case DW_BAD_ENCODING:
355 + (void) fprintf(stderr,
356 + MSG_INTL(MSG_ERR_DWBADENC),
357 + state->file, state->sh_name,
358 + i);
359 + return;
360 + case DW_OVERFLOW:
361 + (void) fprintf(stderr,
362 + MSG_INTL(MSG_ERR_DWOVRFLW),
363 + state->file, state->sh_name);
364 + return;
365 + case DW_SUCCESS:
366 + break;
367 + }
368 + oper1 *= state->ciecalign;
322 369 cur_pc += oper1;
323 370 dbg_print(0, MSG_ORIG(MSG_CFA_ADV_LOC), PREFIX,
324 371 loc_str, EC_XWORD(oper1), EC_XWORD(cur_pc));
325 372 loc_str = MSG_ORIG(MSG_STR_LOC);
326 373 break;
327 374
328 375 case 0x05: /* v2: DW_CFA_offset_extended,reg,off */
329 - oper1 = uleb_extract(&data[off], ndx);
330 - soper = uleb_extract(&data[off], ndx) *
331 - state->ciedalign;
376 + if (uleb_extract(&data[off], ndx, len, &oper1) ==
377 + DW_OVERFLOW) {
378 + (void) fprintf(stderr,
379 + MSG_INTL(MSG_ERR_DWOVRFLW),
380 + state->file, state->sh_name);
381 + return;
382 + }
383 +
384 + if (sleb_extract(&data[off], ndx, len, &soper) ==
385 + DW_OVERFLOW) {
386 + (void) fprintf(stderr,
387 + MSG_INTL(MSG_ERR_DWOVRFLW),
388 + state->file, state->sh_name);
389 + return;
390 + }
391 +
392 + soper *= state->ciedalign;
332 393 dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX,
333 394 REGNAME(oper1, rbuf1), EC_SXWORD(soper));
334 395 break;
335 396
336 397 case 0x06: /* v2: DW_CFA_restore_extended, reg */
337 398 case 0x0d: /* v2: DW_CFA_def_cfa_register, reg */
338 399 case 0x08: /* v2: DW_CFA_same_value, reg */
339 400 case 0x07: /* v2: DW_CFA_undefined, reg */
340 - oper1 = uleb_extract(&data[off], ndx);
401 + if (uleb_extract(&data[off], ndx, len, &oper1) ==
402 + DW_OVERFLOW) {
403 + (void) fprintf(stderr,
404 + MSG_INTL(MSG_ERR_DWOVRFLW),
405 + state->file, state->sh_name);
406 + return;
407 + }
408 +
341 409 dbg_print(0, MSG_ORIG(MSG_CFA_REG), PREFIX,
342 410 REGNAME(oper1, rbuf1));
343 411 break;
344 412
345 413
346 414 case 0x09: /* v2: DW_CFA_register, reg, reg */
347 - oper1 = uleb_extract(&data[off], ndx);
348 - oper2 = uleb_extract(&data[off], ndx);
415 + if (uleb_extract(&data[off], ndx, len, &oper1) ==
416 + DW_OVERFLOW) {
417 + (void) fprintf(stderr,
418 + MSG_INTL(MSG_ERR_DWOVRFLW),
419 + state->file, state->sh_name);
420 + return;
421 + }
422 +
423 + if (uleb_extract(&data[off], ndx, len, &oper2) ==
424 + DW_OVERFLOW) {
425 + (void) fprintf(stderr,
426 + MSG_INTL(MSG_ERR_DWOVRFLW),
427 + state->file, state->sh_name);
428 + return;
429 + }
349 430 dbg_print(0, MSG_ORIG(MSG_CFA_REG_REG), PREFIX,
350 431 REGNAME(oper1, rbuf1), REGNAME(oper2, rbuf2));
351 432 break;
352 433
353 434 case 0x0c: /* v2: DW_CFA_def_cfa, reg, offset */
354 - oper1 = uleb_extract(&data[off], ndx);
355 - oper2 = uleb_extract(&data[off], ndx);
435 + if (uleb_extract(&data[off], ndx, len, &oper1) ==
436 + DW_OVERFLOW) {
437 + (void) fprintf(stderr,
438 + MSG_INTL(MSG_ERR_DWOVRFLW),
439 + state->file, state->sh_name);
440 + return;
441 + }
442 +
443 + if (uleb_extract(&data[off], ndx, len, &oper2) ==
444 + DW_OVERFLOW) {
445 + (void) fprintf(stderr,
446 + MSG_INTL(MSG_ERR_DWOVRFLW),
447 + state->file, state->sh_name);
448 + return;
449 + }
356 450 dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLU), PREFIX,
357 451 REGNAME(oper1, rbuf1), EC_XWORD(oper2));
358 452 break;
359 453
360 454 case 0x0e: /* v2: DW_CFA_def_cfa_offset, offset */
361 - oper1 = uleb_extract(&data[off], ndx);
455 + if (uleb_extract(&data[off], ndx, len, &oper1) ==
456 + DW_OVERFLOW) {
457 + (void) fprintf(stderr,
458 + MSG_INTL(MSG_ERR_DWOVRFLW),
459 + state->file, state->sh_name);
460 + return;
461 + }
362 462 dbg_print(0, MSG_ORIG(MSG_CFA_LLU), PREFIX,
363 463 EC_XWORD(oper1));
364 464 break;
365 465
366 466 case 0x0f: /* v3: DW_CFA_def_cfa_expression, blk */
367 - oper1 = uleb_extract(&data[off], ndx);
467 + if (uleb_extract(&data[off], ndx, len, &oper1) ==
468 + DW_OVERFLOW) {
469 + (void) fprintf(stderr,
470 + MSG_INTL(MSG_ERR_DWOVRFLW),
471 + state->file, state->sh_name);
472 + return;
473 + }
368 474 dbg_print(0, MSG_ORIG(MSG_CFA_EBLK), PREFIX,
369 475 EC_XWORD(oper1));
370 476 /* We currently do not decode the expression block */
371 477 *ndx += oper1;
372 478 break;
373 479
374 480 case 0x10: /* v3: DW_CFA_expression, reg, blk */
375 481 case 0x16: /* v3: DW_CFA_val_expression,reg,blk */
376 - oper1 = uleb_extract(&data[off], ndx);
377 - oper2 = uleb_extract(&data[off], ndx);
482 + if (uleb_extract(&data[off], ndx, len, &oper1) ==
483 + DW_OVERFLOW) {
484 + (void) fprintf(stderr,
485 + MSG_INTL(MSG_ERR_DWOVRFLW),
486 + state->file, state->sh_name);
487 + return;
488 + }
489 +
490 + if (uleb_extract(&data[off], ndx, len, &oper2) ==
491 + DW_OVERFLOW) {
492 + (void) fprintf(stderr,
493 + MSG_INTL(MSG_ERR_DWOVRFLW),
494 + state->file, state->sh_name);
495 + return;
496 + }
378 497 dbg_print(0, MSG_ORIG(MSG_CFA_REG_EBLK), PREFIX,
379 498 REGNAME(oper1, rbuf1), EC_XWORD(oper2));
380 499 /* We currently do not decode the expression block */
381 500 *ndx += oper2;
382 501 break;
383 502
384 503 case 0x11: /* v3: DW_CFA_offset_extended_sf, reg, off */
385 - oper1 = uleb_extract(&data[off], ndx);
386 - soper = sleb_extract(&data[off], ndx) *
387 - state->ciedalign;
504 + if (uleb_extract(&data[off], ndx, len, &oper1) ==
505 + DW_OVERFLOW) {
506 + (void) fprintf(stderr,
507 + MSG_INTL(MSG_ERR_DWOVRFLW),
508 + state->file, state->sh_name);
509 + return;
510 + }
511 +
512 + if (sleb_extract(&data[off], ndx, len, &soper) ==
513 + DW_OVERFLOW) {
514 + (void) fprintf(stderr,
515 + MSG_INTL(MSG_ERR_DWOVRFLW),
516 + state->file, state->sh_name);
517 + return;
518 + }
519 +
520 + soper *= state->ciedalign;
388 521 dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX,
389 522 REGNAME(oper1, rbuf1), EC_SXWORD(soper));
390 523 break;
391 524
392 525 case 0x12: /* v3: DW_CFA_def_cfa_sf, reg, offset */
393 - oper1 = uleb_extract(&data[off], ndx);
394 - soper = sleb_extract(&data[off], ndx) *
395 - state->ciedalign;
526 + if (uleb_extract(&data[off], ndx, len, &oper1) ==
527 + DW_OVERFLOW) {
528 + (void) fprintf(stderr,
529 + MSG_INTL(MSG_ERR_DWOVRFLW),
530 + state->file, state->sh_name);
531 + return;
532 + }
533 +
534 + if (sleb_extract(&data[off], ndx, len, &soper) ==
535 + DW_OVERFLOW) {
536 + (void) fprintf(stderr,
537 + MSG_INTL(MSG_ERR_DWOVRFLW),
538 + state->file, state->sh_name);
539 + return;
540 + }
541 +
542 + soper *= state->ciedalign;
396 543 dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLD), PREFIX,
397 544 REGNAME(oper1, rbuf1), EC_SXWORD(soper));
398 545 break;
399 546
400 547 case 0x13: /* DW_CFA_def_cfa_offset_sf, offset */
401 - soper = sleb_extract(&data[off], ndx) *
402 - state->ciedalign;
548 + if (sleb_extract(&data[off], ndx, len, &soper) ==
549 + DW_OVERFLOW) {
550 + (void) fprintf(stderr,
551 + MSG_INTL(MSG_ERR_DWOVRFLW),
552 + state->file, state->sh_name);
553 + return;
554 + }
555 +
556 + soper *= state->ciedalign;
403 557 dbg_print(0, MSG_ORIG(MSG_CFA_LLD), PREFIX,
404 558 EC_SXWORD(soper));
405 559 break;
406 560
407 561 case 0x14: /* v3: DW_CFA_val_offset, reg, offset */
408 - oper1 = uleb_extract(&data[off], ndx);
409 - soper = uleb_extract(&data[off], ndx) *
410 - state->ciedalign;
562 + if (uleb_extract(&data[off], ndx, len, &oper1) ==
563 + DW_OVERFLOW) {
564 + (void) fprintf(stderr,
565 + MSG_INTL(MSG_ERR_DWOVRFLW),
566 + state->file, state->sh_name);
567 + return;
568 + }
569 +
570 + if (sleb_extract(&data[off], ndx, len, &soper) ==
571 + DW_OVERFLOW) {
572 + (void) fprintf(stderr,
573 + MSG_INTL(MSG_ERR_DWOVRFLW),
574 + state->file, state->sh_name);
575 + return;
576 + }
577 +
578 + soper *= state->ciedalign;
411 579 dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLD), PREFIX,
412 580 REGNAME(oper1, rbuf1), EC_SXWORD(soper));
413 581 break;
414 582
415 583 case 0x15: /* v3: DW_CFA_val_offset_sf, reg, offset */
416 - oper1 = uleb_extract(&data[off], ndx);
417 - soper = sleb_extract(&data[off], ndx) *
418 - state->ciedalign;
584 + if (uleb_extract(&data[off], ndx, len, &oper1) ==
585 + DW_OVERFLOW) {
586 + (void) fprintf(stderr,
587 + MSG_INTL(MSG_ERR_DWOVRFLW),
588 + state->file, state->sh_name);
589 + return;
590 + }
591 +
592 + if (sleb_extract(&data[off], ndx, len, &soper) ==
593 + DW_OVERFLOW) {
594 + (void) fprintf(stderr,
595 + MSG_INTL(MSG_ERR_DWOVRFLW),
596 + state->file, state->sh_name);
597 + return;
598 + }
599 +
600 + soper *= state->ciedalign;
419 601 dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLD), PREFIX,
420 602 REGNAME(oper1, rbuf1), EC_SXWORD(soper));
421 603 break;
422 604
423 605 case 0x1d: /* GNU: DW_CFA_MIPS_advance_loc8, delta */
424 - oper1 = dwarf_extract_uint(data + off, ndx, i,
425 - state->do_swap) * state->ciecalign;
606 + switch (dwarf_extract_uint(data + off, len,
607 + ndx, 8, state->do_swap, &oper1)) {
608 + case DW_BAD_ENCODING:
609 + (void) fprintf(stderr,
610 + MSG_INTL(MSG_ERR_DWBADENC),
611 + state->file, state->sh_name,
612 + 8);
613 + return;
614 + case DW_OVERFLOW:
615 + (void) fprintf(stderr,
616 + MSG_INTL(MSG_ERR_DWOVRFLW),
617 + state->file, state->sh_name);
618 + return;
619 + case DW_SUCCESS:
620 + break;
621 + }
622 + oper1 *= state->ciecalign;
426 623 cur_pc += oper1;
427 624 dbg_print(0, MSG_ORIG(MSG_CFA_ADV_LOC), PREFIX,
428 625 loc_str, EC_XWORD(oper1), EC_XWORD(cur_pc));
429 626 loc_str = MSG_ORIG(MSG_STR_LOC);
430 627 break;
431 628
432 629 case 0x2e: /* GNU: DW_CFA_GNU_args_size, size */
433 - oper1 = uleb_extract(&data[off], ndx);
630 + if (uleb_extract(&data[off], ndx, len, &oper1) ==
631 + DW_OVERFLOW) {
632 + (void) fprintf(stderr,
633 + MSG_INTL(MSG_ERR_DWOVRFLW),
634 + state->file, state->sh_name);
635 + return;
636 + }
637 +
434 638 dbg_print(0, MSG_ORIG(MSG_CFA_LLU), PREFIX,
435 639 EC_XWORD(oper1));
436 640
437 641 break;
438 642
439 643 case 0x2f: /* GNU:DW_CFA_GNU_negative_offset_extended,reg,off */
440 - oper1 = uleb_extract(&data[off], ndx);
441 - soper = -uleb_extract(&data[off], ndx) *
442 - state->ciedalign;
644 + if (uleb_extract(&data[off], ndx, len, &oper1) ==
645 + DW_OVERFLOW) {
646 + (void) fprintf(stderr,
647 + MSG_INTL(MSG_ERR_DWOVRFLW),
648 + state->file, state->sh_name);
649 + return;
650 + }
651 +
652 + if (sleb_extract(&data[off], ndx, len, &soper) ==
653 + DW_OVERFLOW) {
654 + (void) fprintf(stderr,
655 + MSG_INTL(MSG_ERR_DWOVRFLW),
656 + state->file, state->sh_name);
657 + return;
658 + }
659 + soper = -soper * state->ciedalign;
660 + soper *= state->ciedalign;
443 661 dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX,
444 662 REGNAME(oper1, rbuf1), EC_SXWORD(soper));
445 663 break;
446 664
447 665 default:
448 666 /*
449 667 * Unrecognized OP code: DWARF data is variable length,
450 668 * so we don't know how many bytes to skip in order to
451 669 * advance to the next item. We cannot decode beyond
452 670 * this point, so dump the remainder in hex.
453 671 */
454 672 (*ndx)--; /* Back up to unrecognized opcode */
455 673 dump_hex_bytes(data + off + *ndx, len - *ndx,
456 674 indent, 8, 1);
457 675 (*ndx) = len;
↓ open down ↓ |
5 lines elided |
↑ open up ↑ |
458 676 break;
459 677 }
460 678 }
461 679
462 680 #undef PREFIX
463 681 #undef REGNAME
464 682 #undef LOW_OP
465 683 }
466 684
467 685 void
468 -dump_eh_frame(uchar_t *data, size_t datasize, uint64_t sh_addr,
469 - Half e_machine, uchar_t *e_ident, uint64_t gotaddr)
686 +dump_eh_frame(const char *file, char *sh_name, uchar_t *data, size_t datasize,
687 + uint64_t sh_addr, Half e_machine, uchar_t *e_ident, uint64_t gotaddr)
470 688 {
471 689 Conv_dwarf_ehe_buf_t dwarf_ehe_buf;
472 690 dump_cfi_state_t cfi_state;
473 - uint64_t off, ndx;
691 + uint64_t off, ndx, length, id;
474 692 uint_t cieid, cielength, cieversion, cieretaddr;
475 - int ciePflag, cieZflag, cieLflag, cieLflag_present;
476 - uint_t cieaugndx, length, id;
477 - char *cieaugstr;
693 + int ciePflag = 0, cieZflag = 0, cieLflag = 0;
694 + int cieLflag_present = 0;
695 + uint_t cieaugndx;
696 + char *cieaugstr = NULL;
697 + boolean_t have_cie = B_FALSE;
478 698
699 + cfi_state.file = file;
700 + cfi_state.sh_name = sh_name;
479 701 cfi_state.e_machine = e_machine;
480 702 cfi_state.e_ident = e_ident;
481 703 cfi_state.sh_addr = sh_addr;
482 704 cfi_state.do_swap = _elf_sys_encoding() != e_ident[EI_DATA];
483 705 cfi_state.gotaddr = gotaddr;
484 706
485 707 off = 0;
486 708 while (off < datasize) {
487 709 ndx = 0;
488 710
489 711 /*
490 712 * Extract length in native format. A zero length indicates
491 713 * that this CIE is a terminator and that processing for this
492 714 * unwind information should end. However, skip this entry and
493 715 * keep processing, just in case there is any other information
494 716 * remaining in this section. Note, ld(1) will terminate the
495 717 * processing of the .eh_frame contents for this file after a
496 718 * zero length CIE, thus any information that does follow is
497 719 * ignored by ld(1), and is therefore questionable.
498 720 */
499 - length = (uint_t)dwarf_extract_uint(data + off, &ndx,
500 - 4, cfi_state.do_swap);
721 + if (dwarf_extract_uint(data + off, datasize - off,
722 + &ndx, 4, cfi_state.do_swap, &length) == DW_OVERFLOW) {
723 + (void) fprintf(stderr,
724 + MSG_INTL(MSG_ERR_DWOVRFLW),
725 + file, sh_name);
726 + return;
727 + }
728 +
501 729 if (length == 0) {
502 730 dbg_print(0, MSG_ORIG(MSG_UNW_ZEROTERM));
503 731 off += 4;
504 732 continue;
505 733 }
506 734
735 + if (length > (datasize - off)) {
736 + (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADCIEFDELEN),
737 + file, sh_name, EC_XWORD(length),
738 + EC_XWORD(sh_addr + off));
739 + /*
740 + * If length is wrong, we have no means to find the
741 + * next entry, just give up
742 + */
743 + return;
744 + }
745 +
507 746 /*
508 747 * extract CIE id in native format
509 748 */
510 - id = (uint_t)dwarf_extract_uint(data + off, &ndx,
511 - 4, cfi_state.do_swap);
749 + if (dwarf_extract_uint(data + off, datasize - off, &ndx,
750 + 4, cfi_state.do_swap, &id) == DW_OVERFLOW) {
751 + (void) fprintf(stderr,
752 + MSG_INTL(MSG_ERR_DWOVRFLW),
753 + file, sh_name);
754 + return;
755 + }
512 756
513 757 /*
514 758 * A CIE record has an id of '0', otherwise this is a
515 759 * FDE entry and the 'id' is the CIE pointer.
516 760 */
517 761 if (id == 0) {
518 - uint64_t persVal, ndx_save;
519 - uint_t axsize;
762 + uint64_t persVal, ndx_save = 0;
763 + uint64_t axsize;
520 764
765 +
766 + have_cie = B_TRUE;
521 767 cielength = length;
522 768 cieid = id;
523 769 ciePflag = cfi_state.cieRflag = cieZflag = 0;
524 770 cieLflag = cieLflag_present = 0;
525 771
526 772 dbg_print(0, MSG_ORIG(MSG_UNW_CIE),
527 773 EC_XWORD(sh_addr + off));
528 774 dbg_print(0, MSG_ORIG(MSG_UNW_CIELNGTH),
529 775 cielength, cieid);
530 776
531 777 cieversion = data[off + ndx];
532 778 ndx += 1;
533 779 cieaugstr = (char *)(&data[off + ndx]);
534 780 ndx += strlen(cieaugstr) + 1;
535 781
536 782 dbg_print(0, MSG_ORIG(MSG_UNW_CIEVERS),
537 783 cieversion, cieaugstr);
538 784
539 - cfi_state.ciecalign = uleb_extract(&data[off], &ndx);
540 - cfi_state.ciedalign = sleb_extract(&data[off], &ndx);
785 + if (uleb_extract(&data[off], &ndx, datasize - off,
786 + &cfi_state.ciecalign) == DW_OVERFLOW) {
787 + (void) fprintf(stderr,
788 + MSG_INTL(MSG_ERR_DWOVRFLW),
789 + file, sh_name);
790 + return;
791 + }
792 +
793 + if (sleb_extract(&data[off], &ndx, datasize - off,
794 + &cfi_state.ciedalign) == DW_OVERFLOW) {
795 + (void) fprintf(stderr,
796 + MSG_INTL(MSG_ERR_DWOVRFLW),
797 + file, sh_name);
798 + return;
799 + }
541 800 cieretaddr = data[off + ndx];
542 801 ndx += 1;
543 802
544 803 dbg_print(0, MSG_ORIG(MSG_UNW_CIECALGN),
545 804 EC_XWORD(cfi_state.ciecalign),
546 805 EC_XWORD(cfi_state.ciedalign), cieretaddr);
547 806
548 807 if (cieaugstr[0])
549 808 dbg_print(0, MSG_ORIG(MSG_UNW_CIEAXVAL));
550 809
551 810 for (cieaugndx = 0; cieaugstr[cieaugndx]; cieaugndx++) {
552 811 switch (cieaugstr[cieaugndx]) {
553 812 case 'z':
554 - axsize = uleb_extract(&data[off], &ndx);
813 + if (uleb_extract(&data[off], &ndx,
814 + datasize - off, &axsize) ==
815 + DW_OVERFLOW) {
816 + (void) fprintf(stderr,
817 + MSG_INTL(MSG_ERR_DWOVRFLW),
818 + file, sh_name);
819 + return;
820 + }
821 +
555 822 dbg_print(0, MSG_ORIG(MSG_UNW_CIEAXSIZ),
556 - axsize);
823 + EC_XWORD(axsize));
557 824 cieZflag = 1;
558 825 /*
559 826 * The auxiliary section can contain
560 827 * unused padding bytes at the end, so
561 828 * save the current index. Along with
562 829 * axsize, we will use it to set ndx to
563 830 * the proper continuation index after
564 831 * the aux data has been processed.
565 832 */
566 833 ndx_save = ndx;
567 834 break;
568 835 case 'P':
569 836 ciePflag = data[off + ndx];
570 837 ndx += 1;
571 838
572 - persVal = dwarf_ehe_extract(&data[off],
573 - &ndx, ciePflag, e_ident, B_FALSE,
574 - sh_addr, off + ndx, gotaddr);
839 + switch (dwarf_ehe_extract(&data[off],
840 + datasize - off, &ndx, &persVal,
841 + ciePflag, e_ident, B_FALSE, sh_addr,
842 + off + ndx, gotaddr)) {
843 + case DW_OVERFLOW:
844 + (void) fprintf(stderr,
845 + MSG_INTL(MSG_ERR_DWOVRFLW),
846 + file, sh_name);
847 + return;
848 + case DW_BAD_ENCODING:
849 + (void) fprintf(stderr,
850 + MSG_INTL(MSG_ERR_DWBADENC),
851 + file, sh_name, ciePflag);
852 + return;
853 + case DW_SUCCESS:
854 + break;
855 + }
575 856 dbg_print(0,
576 857 MSG_ORIG(MSG_UNW_CIEAXPERS));
577 858 dbg_print(0,
578 859 MSG_ORIG(MSG_UNW_CIEAXPERSENC),
579 860 ciePflag, conv_dwarf_ehe(ciePflag,
580 861 &dwarf_ehe_buf));
581 862 dbg_print(0,
582 863 MSG_ORIG(MSG_UNW_CIEAXPERSRTN),
583 864 EC_XWORD(persVal));
584 865 break;
585 866 case 'R':
586 867 cfi_state.cieRflag = data[off + ndx];
587 868 ndx += 1;
588 869 dbg_print(0,
589 870 MSG_ORIG(MSG_UNW_CIEAXCENC),
590 871 cfi_state.cieRflag,
591 872 conv_dwarf_ehe(cfi_state.cieRflag,
592 873 &dwarf_ehe_buf));
593 874 break;
594 875 case 'L':
595 876 cieLflag_present = 1;
596 877 cieLflag = data[off + ndx];
597 878 ndx += 1;
598 879 dbg_print(0,
599 880 MSG_ORIG(MSG_UNW_CIEAXLSDA),
600 881 cieLflag, conv_dwarf_ehe(
601 882 cieLflag, &dwarf_ehe_buf));
602 883 break;
603 884 default:
604 885 dbg_print(0,
605 886 MSG_ORIG(MSG_UNW_CIEAXUNEC),
606 887 cieaugstr[cieaugndx]);
607 888 break;
608 889 }
609 890 }
610 891
611 892 /*
612 893 * If the z flag was present, reposition ndx using the
613 894 * length given. This will safely move us past any
614 895 * unaccessed padding bytes in the auxiliary section.
615 896 */
616 897 if (cieZflag)
617 898 ndx = ndx_save + axsize;
618 899
619 900 /*
620 901 * Any remaining data are Call Frame Instructions
621 902 */
↓ open down ↓ |
37 lines elided |
↑ open up ↑ |
622 903 if ((cielength + 4) > ndx)
623 904 dump_cfi(data, off, &ndx, cielength, &cfi_state,
624 905 MSG_ORIG(MSG_UNW_CIECFI), 3);
625 906 off += cielength + 4;
626 907
627 908 } else {
628 909 uint_t fdelength = length;
629 910 int fdecieptr = id;
630 911 uint64_t fdeaddrrange;
631 912
913 + if (!have_cie) {
914 + (void) fprintf(stderr,
915 + MSG_INTL(MSG_ERR_DWNOCIE), file, sh_name);
916 + return;
917 + }
918 +
632 919 dbg_print(0, MSG_ORIG(MSG_UNW_FDE),
633 920 EC_XWORD(sh_addr + off));
634 921 dbg_print(0, MSG_ORIG(MSG_UNW_FDELNGTH),
635 922 fdelength, fdecieptr);
636 923
637 - cfi_state.fdeinitloc = dwarf_ehe_extract(&data[off],
638 - &ndx, cfi_state.cieRflag, e_ident, B_FALSE,
639 - sh_addr, off + ndx, gotaddr);
640 - fdeaddrrange = dwarf_ehe_extract(&data[off], &ndx,
641 - (cfi_state.cieRflag & ~DW_EH_PE_pcrel),
642 - e_ident, B_FALSE, sh_addr, off + ndx, gotaddr);
924 + switch (dwarf_ehe_extract(&data[off], datasize - off,
925 + &ndx, &cfi_state.fdeinitloc, cfi_state.cieRflag,
926 + e_ident, B_FALSE, sh_addr, off + ndx, gotaddr)) {
927 + case DW_OVERFLOW:
928 + (void) fprintf(stderr,
929 + MSG_INTL(MSG_ERR_DWOVRFLW), file, sh_name);
930 + return;
931 + case DW_BAD_ENCODING:
932 + (void) fprintf(stderr,
933 + MSG_INTL(MSG_ERR_DWBADENC), file, sh_name,
934 + cfi_state.cieRflag);
935 + return;
936 + case DW_SUCCESS:
937 + break;
938 + }
939 +
940 + switch (dwarf_ehe_extract(&data[off], datasize - off,
941 + &ndx, &fdeaddrrange,
942 + (cfi_state.cieRflag & ~DW_EH_PE_pcrel), e_ident,
943 + B_FALSE, sh_addr, off + ndx, gotaddr)) {
944 + case DW_OVERFLOW:
945 + (void) fprintf(stderr,
946 + MSG_INTL(MSG_ERR_DWOVRFLW), file, sh_name);
947 + return;
948 + case DW_BAD_ENCODING:
949 + (void) fprintf(stderr,
950 + MSG_INTL(MSG_ERR_DWBADENC), file, sh_name,
951 + (cfi_state.cieRflag & ~DW_EH_PE_pcrel));
952 + return;
953 + case DW_SUCCESS:
954 + break;
955 + }
643 956
644 957 dbg_print(0, MSG_ORIG(MSG_UNW_FDEINITLOC),
645 958 EC_XWORD(cfi_state.fdeinitloc),
646 959 EC_XWORD(fdeaddrrange),
647 960 EC_XWORD(cfi_state.fdeinitloc + fdeaddrrange - 1));
648 961
649 - if (cieaugstr[0])
962 + if ((cieaugstr != NULL) && (cieaugstr[0] != '\0'))
650 963 dbg_print(0, MSG_ORIG(MSG_UNW_FDEAXVAL));
651 964 if (cieZflag) {
652 965 uint64_t val;
653 966 uint64_t lndx;
654 967
655 - val = uleb_extract(&data[off], &ndx);
968 + if (uleb_extract(&data[off], &ndx,
969 + datasize - off, &val) == DW_OVERFLOW) {
970 + (void) fprintf(stderr,
971 + MSG_INTL(MSG_ERR_DWOVRFLW),
972 + file, sh_name);
973 + return;
974 + }
656 975 lndx = ndx;
657 976 ndx += val;
658 977 dbg_print(0, MSG_ORIG(MSG_UNW_FDEAXSIZE),
659 978 EC_XWORD(val));
660 979 if (val && cieLflag_present) {
661 980 uint64_t lsda;
662 981
663 - lsda = dwarf_ehe_extract(&data[off],
664 - &lndx, cieLflag, e_ident,
665 - B_FALSE, sh_addr, off + lndx,
666 - gotaddr);
982 + switch (dwarf_ehe_extract(&data[off],
983 + datasize - off, &lndx, &lsda,
984 + cieLflag, e_ident, B_FALSE, sh_addr,
985 + off + lndx, gotaddr)) {
986 + case DW_OVERFLOW:
987 + (void) fprintf(stderr,
988 + MSG_INTL(MSG_ERR_DWOVRFLW),
989 + file, sh_name);
990 + return;
991 + case DW_BAD_ENCODING:
992 + (void) fprintf(stderr,
993 + MSG_INTL(MSG_ERR_DWBADENC),
994 + file, sh_name, cieLflag);
995 + return;
996 + case DW_SUCCESS:
997 + break;
998 + }
667 999 dbg_print(0,
668 1000 MSG_ORIG(MSG_UNW_FDEAXLSDA),
669 1001 EC_XWORD(lsda));
670 1002 }
671 1003 }
672 1004 if ((fdelength + 4) > ndx)
673 1005 dump_cfi(data, off, &ndx, fdelength, &cfi_state,
674 1006 MSG_ORIG(MSG_UNW_FDECFI), 6);
675 1007 off += fdelength + 4;
676 1008 }
677 1009 }
678 1010 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX