njn | 4bbdc97 | 2003-10-16 10:10:55 +0000 | [diff] [blame] | 1 | /*--------------------------------------------------------------------*/ |
jseward | 8b3131a | 2003-12-13 23:16:26 +0000 | [diff] [blame] | 2 | /*--- Read DWARF2 debug info. vg_dwarf.c ---*/ |
njn | 4bbdc97 | 2003-10-16 10:10:55 +0000 | [diff] [blame] | 3 | /*--------------------------------------------------------------------*/ |
| 4 | |
| 5 | /* |
njn | b9c427c | 2004-12-01 14:14:42 +0000 | [diff] [blame] | 6 | This file is part of Valgrind, a dynamic binary instrumentation |
| 7 | framework. |
njn | 4bbdc97 | 2003-10-16 10:10:55 +0000 | [diff] [blame] | 8 | |
njn | 5361242 | 2005-03-12 16:22:54 +0000 | [diff] [blame] | 9 | Copyright (C) 2000-2005 Julian Seward |
njn | 4bbdc97 | 2003-10-16 10:10:55 +0000 | [diff] [blame] | 10 | jseward@acm.org |
| 11 | |
| 12 | This program is free software; you can redistribute it and/or |
| 13 | modify it under the terms of the GNU General Public License as |
| 14 | published by the Free Software Foundation; either version 2 of the |
| 15 | License, or (at your option) any later version. |
| 16 | |
| 17 | This program is distributed in the hope that it will be useful, but |
| 18 | WITHOUT ANY WARRANTY; without even the implied warranty of |
| 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 20 | General Public License for more details. |
| 21 | |
| 22 | You should have received a copy of the GNU General Public License |
| 23 | along with this program; if not, write to the Free Software |
| 24 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
| 25 | 02111-1307, USA. |
| 26 | |
| 27 | The GNU General Public License is contained in the file COPYING. |
| 28 | */ |
jsgf | cb1d1c0 | 2003-10-14 21:55:10 +0000 | [diff] [blame] | 29 | |
nethercote | f1e5e15 | 2004-09-01 23:58:16 +0000 | [diff] [blame] | 30 | #include "core.h" |
jsgf | cb1d1c0 | 2003-10-14 21:55:10 +0000 | [diff] [blame] | 31 | #include "vg_symtab2.h" |
| 32 | |
| 33 | |
jsgf | cb1d1c0 | 2003-10-14 21:55:10 +0000 | [diff] [blame] | 34 | /* Structure found in the .debug_line section. */ |
| 35 | typedef struct |
| 36 | { |
| 37 | UChar li_length [4]; |
| 38 | UChar li_version [2]; |
| 39 | UChar li_prologue_length [4]; |
| 40 | UChar li_min_insn_length [1]; |
| 41 | UChar li_default_is_stmt [1]; |
| 42 | UChar li_line_base [1]; |
| 43 | UChar li_line_range [1]; |
| 44 | UChar li_opcode_base [1]; |
| 45 | } |
| 46 | DWARF2_External_LineInfo; |
| 47 | |
| 48 | typedef struct |
| 49 | { |
| 50 | UInt li_length; |
| 51 | UShort li_version; |
| 52 | UInt li_prologue_length; |
| 53 | UChar li_min_insn_length; |
| 54 | UChar li_default_is_stmt; |
| 55 | Int li_line_base; |
| 56 | UChar li_line_range; |
| 57 | UChar li_opcode_base; |
| 58 | } |
| 59 | DWARF2_Internal_LineInfo; |
| 60 | |
| 61 | /* Line number opcodes. */ |
| 62 | enum dwarf_line_number_ops |
| 63 | { |
| 64 | DW_LNS_extended_op = 0, |
| 65 | DW_LNS_copy = 1, |
| 66 | DW_LNS_advance_pc = 2, |
| 67 | DW_LNS_advance_line = 3, |
| 68 | DW_LNS_set_file = 4, |
| 69 | DW_LNS_set_column = 5, |
| 70 | DW_LNS_negate_stmt = 6, |
| 71 | DW_LNS_set_basic_block = 7, |
| 72 | DW_LNS_const_add_pc = 8, |
| 73 | DW_LNS_fixed_advance_pc = 9, |
| 74 | /* DWARF 3. */ |
| 75 | DW_LNS_set_prologue_end = 10, |
| 76 | DW_LNS_set_epilogue_begin = 11, |
| 77 | DW_LNS_set_isa = 12 |
| 78 | }; |
| 79 | |
| 80 | /* Line number extended opcodes. */ |
| 81 | enum dwarf_line_number_x_ops |
| 82 | { |
| 83 | DW_LNE_end_sequence = 1, |
| 84 | DW_LNE_set_address = 2, |
| 85 | DW_LNE_define_file = 3 |
| 86 | }; |
| 87 | |
| 88 | typedef struct State_Machine_Registers |
| 89 | { |
| 90 | /* Information for the last statement boundary. |
| 91 | * Needed to calculate statement lengths. */ |
| 92 | Addr last_address; |
| 93 | UInt last_file; |
| 94 | UInt last_line; |
| 95 | |
| 96 | Addr address; |
| 97 | UInt file; |
| 98 | UInt line; |
| 99 | UInt column; |
| 100 | Int is_stmt; |
| 101 | Int basic_block; |
| 102 | Int end_sequence; |
| 103 | /* This variable hold the number of the last entry seen |
| 104 | in the File Table. */ |
| 105 | UInt last_file_entry; |
| 106 | } SMR; |
| 107 | |
| 108 | |
| 109 | static |
| 110 | UInt read_leb128 ( UChar* data, Int* length_return, Int sign ) |
| 111 | { |
| 112 | UInt result = 0; |
| 113 | UInt num_read = 0; |
| 114 | Int shift = 0; |
| 115 | UChar byte; |
| 116 | |
| 117 | do |
| 118 | { |
| 119 | byte = * data ++; |
| 120 | num_read ++; |
| 121 | |
| 122 | result |= (byte & 0x7f) << shift; |
| 123 | |
| 124 | shift += 7; |
| 125 | |
| 126 | } |
| 127 | while (byte & 0x80); |
| 128 | |
| 129 | if (length_return != NULL) |
| 130 | * length_return = num_read; |
| 131 | |
| 132 | if (sign && (shift < 32) && (byte & 0x40)) |
| 133 | result |= -1 << shift; |
| 134 | |
| 135 | return result; |
| 136 | } |
| 137 | |
| 138 | |
| 139 | static SMR state_machine_regs; |
| 140 | |
| 141 | static |
| 142 | void reset_state_machine ( Int is_stmt ) |
| 143 | { |
| 144 | if (0) VG_(printf)("smr.a := %p (reset)\n", 0 ); |
| 145 | state_machine_regs.last_address = 0; |
| 146 | state_machine_regs.last_file = 1; |
| 147 | state_machine_regs.last_line = 1; |
| 148 | state_machine_regs.address = 0; |
| 149 | state_machine_regs.file = 1; |
| 150 | state_machine_regs.line = 1; |
| 151 | state_machine_regs.column = 0; |
| 152 | state_machine_regs.is_stmt = is_stmt; |
| 153 | state_machine_regs.basic_block = 0; |
| 154 | state_machine_regs.end_sequence = 0; |
| 155 | state_machine_regs.last_file_entry = 0; |
| 156 | } |
| 157 | |
| 158 | /* Handled an extend line op. Returns true if this is the end |
| 159 | of sequence. */ |
| 160 | static |
| 161 | int process_extended_line_op( SegInfo *si, Char*** fnames, |
| 162 | UChar* data, Int is_stmt, Int pointer_size) |
| 163 | { |
| 164 | UChar op_code; |
| 165 | Int bytes_read; |
| 166 | UInt len; |
| 167 | UChar * name; |
| 168 | Addr adr; |
| 169 | |
| 170 | len = read_leb128 (data, & bytes_read, 0); |
| 171 | data += bytes_read; |
| 172 | |
| 173 | if (len == 0) |
| 174 | { |
| 175 | VG_(message)(Vg_UserMsg, |
| 176 | "badly formed extended line op encountered!\n"); |
| 177 | return bytes_read; |
| 178 | } |
| 179 | |
| 180 | len += bytes_read; |
| 181 | op_code = * data ++; |
| 182 | |
| 183 | if (0) VG_(printf)("dwarf2: ext OPC: %d\n", op_code); |
| 184 | |
| 185 | switch (op_code) |
| 186 | { |
| 187 | case DW_LNE_end_sequence: |
| 188 | if (0) VG_(printf)("1001: si->o %p, smr.a %p\n", |
| 189 | si->offset, state_machine_regs.address ); |
| 190 | state_machine_regs.end_sequence = 1; /* JRS: added for compliance |
| 191 | with spec; is pointless due to reset_state_machine below |
| 192 | */ |
| 193 | if (state_machine_regs.is_stmt) { |
| 194 | if (state_machine_regs.last_address) |
| 195 | VG_(addLineInfo) (si, (*fnames)[state_machine_regs.last_file], |
| 196 | si->offset + state_machine_regs.last_address, |
| 197 | si->offset + state_machine_regs.address, |
| 198 | state_machine_regs.last_line, 0); |
| 199 | } |
| 200 | reset_state_machine (is_stmt); |
| 201 | break; |
| 202 | |
| 203 | case DW_LNE_set_address: |
| 204 | /* XXX: Pointer size could be 8 */ |
njn | bde3027 | 2004-11-29 15:45:31 +0000 | [diff] [blame] | 205 | // (and there may be other 32-bit assumptions within this file? |
| 206 | // not sure... --njn) |
jsgf | cb1d1c0 | 2003-10-14 21:55:10 +0000 | [diff] [blame] | 207 | vg_assert(pointer_size == 4); |
| 208 | adr = *((Addr *)data); |
| 209 | if (0) VG_(printf)("smr.a := %p\n", adr ); |
| 210 | state_machine_regs.address = adr; |
| 211 | break; |
| 212 | |
| 213 | case DW_LNE_define_file: |
| 214 | ++ state_machine_regs.last_file_entry; |
| 215 | name = data; |
| 216 | if (*fnames == NULL) |
| 217 | *fnames = VG_(arena_malloc)(VG_AR_SYMTAB, sizeof (UInt) * 2); |
| 218 | else |
| 219 | *fnames = VG_(arena_realloc)( |
njn | 828022a | 2005-03-13 14:56:31 +0000 | [diff] [blame] | 220 | VG_AR_SYMTAB, *fnames, |
| 221 | sizeof(UInt) * (state_machine_regs.last_file_entry + 1)); |
jsgf | cb1d1c0 | 2003-10-14 21:55:10 +0000 | [diff] [blame] | 222 | (*fnames)[state_machine_regs.last_file_entry] = VG_(addStr) (si,name, -1); |
| 223 | data += VG_(strlen) ((char *) data) + 1; |
| 224 | read_leb128 (data, & bytes_read, 0); |
| 225 | data += bytes_read; |
| 226 | read_leb128 (data, & bytes_read, 0); |
| 227 | data += bytes_read; |
| 228 | read_leb128 (data, & bytes_read, 0); |
| 229 | break; |
| 230 | |
| 231 | default: |
| 232 | break; |
| 233 | } |
| 234 | |
| 235 | return len; |
| 236 | } |
| 237 | |
| 238 | |
| 239 | void VG_(read_debuginfo_dwarf2) ( SegInfo* si, UChar* dwarf2, Int dwarf2_sz ) |
| 240 | { |
| 241 | DWARF2_External_LineInfo * external; |
| 242 | DWARF2_Internal_LineInfo info; |
| 243 | UChar * standard_opcodes; |
| 244 | UChar * data = dwarf2; |
| 245 | UChar * end = dwarf2 + dwarf2_sz; |
| 246 | UChar * end_of_sequence; |
| 247 | Char ** fnames = NULL; |
| 248 | |
| 249 | /* Fails due to gcc padding ... |
| 250 | vg_assert(sizeof(DWARF2_External_LineInfo) |
| 251 | == sizeof(DWARF2_Internal_LineInfo)); |
| 252 | */ |
| 253 | |
| 254 | while (data < end) |
| 255 | { |
| 256 | external = (DWARF2_External_LineInfo *) data; |
| 257 | |
| 258 | /* Check the length of the block. */ |
| 259 | info.li_length = * ((UInt *)(external->li_length)); |
| 260 | |
| 261 | if (info.li_length == 0xffffffff) |
| 262 | { |
| 263 | VG_(symerr)("64-bit DWARF line info is not supported yet."); |
| 264 | break; |
| 265 | } |
| 266 | |
| 267 | if (info.li_length + sizeof (external->li_length) > dwarf2_sz) |
| 268 | { |
| 269 | VG_(symerr)("DWARF line info appears to be corrupt " |
| 270 | "- the section is too small"); |
| 271 | return; |
| 272 | } |
| 273 | |
| 274 | /* Check its version number. */ |
| 275 | info.li_version = * ((UShort *) (external->li_version)); |
| 276 | if (info.li_version != 2) |
| 277 | { |
| 278 | VG_(symerr)("Only DWARF version 2 line info " |
| 279 | "is currently supported."); |
| 280 | return; |
| 281 | } |
| 282 | |
| 283 | info.li_prologue_length = * ((UInt *) (external->li_prologue_length)); |
| 284 | info.li_min_insn_length = * ((UChar *)(external->li_min_insn_length)); |
| 285 | |
| 286 | info.li_default_is_stmt = True; |
| 287 | /* WAS: = * ((UChar *)(external->li_default_is_stmt)); */ |
| 288 | /* Josef Weidendorfer (20021021) writes: |
| 289 | |
| 290 | It seems to me that the Intel Fortran compiler generates |
| 291 | bad DWARF2 line info code: It sets "is_stmt" of the state |
| 292 | machine in the the line info reader to be always |
| 293 | false. Thus, there is never a statement boundary generated |
| 294 | and therefore never a instruction range/line number |
| 295 | mapping generated for valgrind. |
| 296 | |
| 297 | Please have a look at the DWARF2 specification, Ch. 6.2 |
| 298 | (x86.ddj.com/ftp/manuals/tools/dwarf.pdf). Perhaps I |
| 299 | understand this wrong, but I don't think so. |
| 300 | |
| 301 | I just had a look at the GDB DWARF2 reader... They |
| 302 | completely ignore "is_stmt" when recording line info ;-) |
| 303 | That's the reason "objdump -S" works on files from the the |
| 304 | intel fortran compiler. |
| 305 | */ |
| 306 | |
| 307 | |
| 308 | /* JRS: changed (UInt*) to (UChar*) */ |
| 309 | info.li_line_base = * ((UChar *)(external->li_line_base)); |
| 310 | |
| 311 | info.li_line_range = * ((UChar *)(external->li_line_range)); |
| 312 | info.li_opcode_base = * ((UChar *)(external->li_opcode_base)); |
| 313 | |
| 314 | if (0) VG_(printf)("dwarf2: line base: %d, range %d, opc base: %d\n", |
| 315 | info.li_line_base, info.li_line_range, info.li_opcode_base); |
| 316 | |
| 317 | /* Sign extend the line base field. */ |
| 318 | info.li_line_base <<= 24; |
| 319 | info.li_line_base >>= 24; |
| 320 | |
| 321 | end_of_sequence = data + info.li_length |
| 322 | + sizeof (external->li_length); |
| 323 | |
| 324 | reset_state_machine (info.li_default_is_stmt); |
| 325 | |
| 326 | /* Read the contents of the Opcodes table. */ |
| 327 | standard_opcodes = data + sizeof (* external); |
| 328 | |
| 329 | /* Read the contents of the Directory table. */ |
| 330 | data = standard_opcodes + info.li_opcode_base - 1; |
| 331 | |
| 332 | if (* data == 0) |
| 333 | { |
| 334 | } |
| 335 | else |
| 336 | { |
| 337 | /* We ignore the directory table, since gcc gives the entire |
| 338 | path as part of the filename */ |
| 339 | while (* data != 0) |
| 340 | { |
| 341 | data += VG_(strlen) ((char *) data) + 1; |
| 342 | } |
| 343 | } |
| 344 | |
| 345 | /* Skip the NUL at the end of the table. */ |
| 346 | if (*data != 0) { |
| 347 | VG_(symerr)("can't find NUL at end of DWARF2 directory table"); |
| 348 | return; |
| 349 | } |
| 350 | data ++; |
| 351 | |
| 352 | /* Read the contents of the File Name table. */ |
| 353 | if (* data == 0) |
| 354 | { |
| 355 | } |
| 356 | else |
| 357 | { |
| 358 | while (* data != 0) |
| 359 | { |
| 360 | UChar * name; |
| 361 | Int bytes_read; |
| 362 | |
| 363 | ++ state_machine_regs.last_file_entry; |
| 364 | name = data; |
| 365 | /* Since we don't have realloc (0, ....) == malloc (...) |
| 366 | semantics, we need to malloc the first time. */ |
| 367 | |
| 368 | if (fnames == NULL) |
| 369 | fnames = VG_(arena_malloc)(VG_AR_SYMTAB, sizeof (UInt) * 2); |
| 370 | else |
nethercote | 2d5b816 | 2004-08-11 09:40:52 +0000 | [diff] [blame] | 371 | fnames = VG_(arena_realloc)(VG_AR_SYMTAB, fnames, |
jsgf | cb1d1c0 | 2003-10-14 21:55:10 +0000 | [diff] [blame] | 372 | sizeof(UInt) |
| 373 | * (state_machine_regs.last_file_entry + 1)); |
| 374 | data += VG_(strlen) ((Char *) data) + 1; |
| 375 | fnames[state_machine_regs.last_file_entry] = VG_(addStr) (si,name, -1); |
| 376 | |
| 377 | read_leb128 (data, & bytes_read, 0); |
| 378 | data += bytes_read; |
| 379 | read_leb128 (data, & bytes_read, 0); |
| 380 | data += bytes_read; |
| 381 | read_leb128 (data, & bytes_read, 0); |
| 382 | data += bytes_read; |
| 383 | } |
| 384 | } |
| 385 | |
| 386 | /* Skip the NUL at the end of the table. */ |
| 387 | if (*data != 0) { |
| 388 | VG_(symerr)("can't find NUL at end of DWARF2 file name table"); |
| 389 | return; |
| 390 | } |
| 391 | data ++; |
| 392 | |
| 393 | /* Now display the statements. */ |
| 394 | |
| 395 | while (data < end_of_sequence) |
| 396 | { |
| 397 | UChar op_code; |
| 398 | Int adv; |
| 399 | Int bytes_read; |
| 400 | |
| 401 | op_code = * data ++; |
| 402 | |
| 403 | if (0) VG_(printf)("dwarf2: OPC: %d\n", op_code); |
| 404 | |
| 405 | if (op_code >= info.li_opcode_base) |
| 406 | { |
| 407 | Int advAddr; |
| 408 | op_code -= info.li_opcode_base; |
| 409 | adv = (op_code / info.li_line_range) |
| 410 | * info.li_min_insn_length; |
| 411 | advAddr = adv; |
| 412 | state_machine_regs.address += adv; |
| 413 | if (0) VG_(printf)("smr.a += %p\n", adv ); |
| 414 | adv = (op_code % info.li_line_range) + info.li_line_base; |
| 415 | if (0) VG_(printf)("1002: si->o %p, smr.a %p\n", |
| 416 | si->offset, state_machine_regs.address ); |
| 417 | state_machine_regs.line += adv; |
| 418 | |
| 419 | if (state_machine_regs.is_stmt) { |
| 420 | /* only add a statement if there was a previous boundary */ |
| 421 | if (state_machine_regs.last_address) |
| 422 | VG_(addLineInfo) (si, fnames[state_machine_regs.last_file], |
| 423 | si->offset + state_machine_regs.last_address, |
| 424 | si->offset + state_machine_regs.address, |
| 425 | state_machine_regs.last_line, 0); |
| 426 | state_machine_regs.last_address = state_machine_regs.address; |
| 427 | state_machine_regs.last_file = state_machine_regs.file; |
| 428 | state_machine_regs.last_line = state_machine_regs.line; |
| 429 | } |
| 430 | } |
| 431 | else switch (op_code) |
| 432 | { |
| 433 | case DW_LNS_extended_op: |
| 434 | data += process_extended_line_op ( |
| 435 | si, &fnames, data, |
| 436 | info.li_default_is_stmt, sizeof (Addr)); |
| 437 | break; |
| 438 | |
| 439 | case DW_LNS_copy: |
| 440 | if (0) VG_(printf)("1002: si->o %p, smr.a %p\n", |
| 441 | si->offset, state_machine_regs.address ); |
| 442 | if (state_machine_regs.is_stmt) { |
| 443 | /* only add a statement if there was a previous boundary */ |
| 444 | if (state_machine_regs.last_address) |
| 445 | VG_(addLineInfo) (si, fnames[state_machine_regs.last_file], |
| 446 | si->offset + state_machine_regs.last_address, |
| 447 | si->offset + state_machine_regs.address, |
| 448 | state_machine_regs.last_line, 0); |
| 449 | state_machine_regs.last_address = state_machine_regs.address; |
| 450 | state_machine_regs.last_file = state_machine_regs.file; |
| 451 | state_machine_regs.last_line = state_machine_regs.line; |
| 452 | } |
| 453 | state_machine_regs.basic_block = 0; /* JRS added */ |
| 454 | break; |
| 455 | |
| 456 | case DW_LNS_advance_pc: |
| 457 | adv = info.li_min_insn_length |
| 458 | * read_leb128 (data, & bytes_read, 0); |
| 459 | data += bytes_read; |
| 460 | state_machine_regs.address += adv; |
| 461 | if (0) VG_(printf)("smr.a += %p\n", adv ); |
| 462 | break; |
| 463 | |
| 464 | case DW_LNS_advance_line: |
| 465 | adv = read_leb128 (data, & bytes_read, 1); |
| 466 | data += bytes_read; |
| 467 | state_machine_regs.line += adv; |
| 468 | break; |
| 469 | |
| 470 | case DW_LNS_set_file: |
| 471 | adv = read_leb128 (data, & bytes_read, 0); |
| 472 | data += bytes_read; |
| 473 | state_machine_regs.file = adv; |
| 474 | break; |
| 475 | |
| 476 | case DW_LNS_set_column: |
| 477 | adv = read_leb128 (data, & bytes_read, 0); |
| 478 | data += bytes_read; |
| 479 | state_machine_regs.column = adv; |
| 480 | break; |
| 481 | |
| 482 | case DW_LNS_negate_stmt: |
| 483 | adv = state_machine_regs.is_stmt; |
| 484 | adv = ! adv; |
| 485 | state_machine_regs.is_stmt = adv; |
| 486 | break; |
| 487 | |
| 488 | case DW_LNS_set_basic_block: |
| 489 | state_machine_regs.basic_block = 1; |
| 490 | break; |
| 491 | |
| 492 | case DW_LNS_const_add_pc: |
| 493 | adv = (((255 - info.li_opcode_base) / info.li_line_range) |
| 494 | * info.li_min_insn_length); |
| 495 | state_machine_regs.address += adv; |
| 496 | if (0) VG_(printf)("smr.a += %p\n", adv ); |
| 497 | break; |
| 498 | |
| 499 | case DW_LNS_fixed_advance_pc: |
| 500 | /* XXX: Need something to get 2 bytes */ |
| 501 | adv = *((UShort *)data); |
| 502 | data += 2; |
| 503 | state_machine_regs.address += adv; |
| 504 | if (0) VG_(printf)("smr.a += %p\n", adv ); |
| 505 | break; |
| 506 | |
| 507 | case DW_LNS_set_prologue_end: |
| 508 | break; |
| 509 | |
| 510 | case DW_LNS_set_epilogue_begin: |
| 511 | break; |
| 512 | |
| 513 | case DW_LNS_set_isa: |
| 514 | adv = read_leb128 (data, & bytes_read, 0); |
| 515 | data += bytes_read; |
| 516 | break; |
| 517 | |
| 518 | default: |
| 519 | { |
| 520 | int j; |
| 521 | for (j = standard_opcodes[op_code - 1]; j > 0 ; --j) |
| 522 | { |
| 523 | read_leb128 (data, &bytes_read, 0); |
| 524 | data += bytes_read; |
| 525 | } |
| 526 | } |
| 527 | break; |
| 528 | } |
| 529 | } |
| 530 | VG_(arena_free)(VG_AR_SYMTAB, fnames); |
| 531 | fnames = NULL; |
| 532 | } |
| 533 | } |
njn | 4bbdc97 | 2003-10-16 10:10:55 +0000 | [diff] [blame] | 534 | |
jseward | 8b3131a | 2003-12-13 23:16:26 +0000 | [diff] [blame] | 535 | |
| 536 | /*------------------------------------------------------------*/ |
| 537 | /*--- Read DWARF1 format line number info. ---*/ |
| 538 | /*------------------------------------------------------------*/ |
| 539 | |
| 540 | /* DWARF1 appears to be redundant, but nevertheless the Lahey Fortran |
| 541 | compiler generates it. |
| 542 | */ |
| 543 | |
| 544 | /* The following three enums (dwarf_tag, dwarf_form, dwarf_attribute) |
| 545 | are taken from the file include/elf/dwarf.h in the GNU gdb-6.0 |
| 546 | sources, which are Copyright 1992, 1993, 1995, 1999 Free Software |
| 547 | Foundation, Inc and naturally licensed under the GNU General Public |
| 548 | License version 2 or later. |
| 549 | */ |
| 550 | |
| 551 | /* Tag names and codes. */ |
| 552 | |
| 553 | enum dwarf_tag { |
| 554 | TAG_padding = 0x0000, |
| 555 | TAG_array_type = 0x0001, |
| 556 | TAG_class_type = 0x0002, |
| 557 | TAG_entry_point = 0x0003, |
| 558 | TAG_enumeration_type = 0x0004, |
| 559 | TAG_formal_parameter = 0x0005, |
| 560 | TAG_global_subroutine = 0x0006, |
| 561 | TAG_global_variable = 0x0007, |
| 562 | /* 0x0008 -- reserved */ |
| 563 | /* 0x0009 -- reserved */ |
| 564 | TAG_label = 0x000a, |
| 565 | TAG_lexical_block = 0x000b, |
| 566 | TAG_local_variable = 0x000c, |
| 567 | TAG_member = 0x000d, |
| 568 | /* 0x000e -- reserved */ |
| 569 | TAG_pointer_type = 0x000f, |
| 570 | TAG_reference_type = 0x0010, |
| 571 | TAG_compile_unit = 0x0011, |
| 572 | TAG_string_type = 0x0012, |
| 573 | TAG_structure_type = 0x0013, |
| 574 | TAG_subroutine = 0x0014, |
| 575 | TAG_subroutine_type = 0x0015, |
| 576 | TAG_typedef = 0x0016, |
| 577 | TAG_union_type = 0x0017, |
| 578 | TAG_unspecified_parameters = 0x0018, |
| 579 | TAG_variant = 0x0019, |
| 580 | TAG_common_block = 0x001a, |
| 581 | TAG_common_inclusion = 0x001b, |
| 582 | TAG_inheritance = 0x001c, |
| 583 | TAG_inlined_subroutine = 0x001d, |
| 584 | TAG_module = 0x001e, |
| 585 | TAG_ptr_to_member_type = 0x001f, |
| 586 | TAG_set_type = 0x0020, |
| 587 | TAG_subrange_type = 0x0021, |
| 588 | TAG_with_stmt = 0x0022, |
| 589 | |
| 590 | /* GNU extensions */ |
| 591 | |
| 592 | TAG_format_label = 0x8000, /* for FORTRAN 77 and Fortran 90 */ |
| 593 | TAG_namelist = 0x8001, /* For Fortran 90 */ |
| 594 | TAG_function_template = 0x8002, /* for C++ */ |
| 595 | TAG_class_template = 0x8003 /* for C++ */ |
| 596 | }; |
| 597 | |
| 598 | /* Form names and codes. */ |
| 599 | |
| 600 | enum dwarf_form { |
| 601 | FORM_ADDR = 0x1, |
| 602 | FORM_REF = 0x2, |
| 603 | FORM_BLOCK2 = 0x3, |
| 604 | FORM_BLOCK4 = 0x4, |
| 605 | FORM_DATA2 = 0x5, |
| 606 | FORM_DATA4 = 0x6, |
| 607 | FORM_DATA8 = 0x7, |
| 608 | FORM_STRING = 0x8 |
| 609 | }; |
| 610 | |
| 611 | /* Attribute names and codes. */ |
| 612 | |
| 613 | enum dwarf_attribute { |
| 614 | AT_sibling = (0x0010|FORM_REF), |
| 615 | AT_location = (0x0020|FORM_BLOCK2), |
| 616 | AT_name = (0x0030|FORM_STRING), |
| 617 | AT_fund_type = (0x0050|FORM_DATA2), |
| 618 | AT_mod_fund_type = (0x0060|FORM_BLOCK2), |
| 619 | AT_user_def_type = (0x0070|FORM_REF), |
| 620 | AT_mod_u_d_type = (0x0080|FORM_BLOCK2), |
| 621 | AT_ordering = (0x0090|FORM_DATA2), |
| 622 | AT_subscr_data = (0x00a0|FORM_BLOCK2), |
| 623 | AT_byte_size = (0x00b0|FORM_DATA4), |
| 624 | AT_bit_offset = (0x00c0|FORM_DATA2), |
| 625 | AT_bit_size = (0x00d0|FORM_DATA4), |
| 626 | /* (0x00e0|FORM_xxxx) -- reserved */ |
| 627 | AT_element_list = (0x00f0|FORM_BLOCK4), |
| 628 | AT_stmt_list = (0x0100|FORM_DATA4), |
| 629 | AT_low_pc = (0x0110|FORM_ADDR), |
| 630 | AT_high_pc = (0x0120|FORM_ADDR), |
| 631 | AT_language = (0x0130|FORM_DATA4), |
| 632 | AT_member = (0x0140|FORM_REF), |
| 633 | AT_discr = (0x0150|FORM_REF), |
| 634 | AT_discr_value = (0x0160|FORM_BLOCK2), |
| 635 | /* (0x0170|FORM_xxxx) -- reserved */ |
| 636 | /* (0x0180|FORM_xxxx) -- reserved */ |
| 637 | AT_string_length = (0x0190|FORM_BLOCK2), |
| 638 | AT_common_reference = (0x01a0|FORM_REF), |
| 639 | AT_comp_dir = (0x01b0|FORM_STRING), |
| 640 | AT_const_value_string = (0x01c0|FORM_STRING), |
| 641 | AT_const_value_data2 = (0x01c0|FORM_DATA2), |
| 642 | AT_const_value_data4 = (0x01c0|FORM_DATA4), |
| 643 | AT_const_value_data8 = (0x01c0|FORM_DATA8), |
| 644 | AT_const_value_block2 = (0x01c0|FORM_BLOCK2), |
| 645 | AT_const_value_block4 = (0x01c0|FORM_BLOCK4), |
| 646 | AT_containing_type = (0x01d0|FORM_REF), |
| 647 | AT_default_value_addr = (0x01e0|FORM_ADDR), |
| 648 | AT_default_value_data2 = (0x01e0|FORM_DATA2), |
| 649 | AT_default_value_data4 = (0x01e0|FORM_DATA4), |
| 650 | AT_default_value_data8 = (0x01e0|FORM_DATA8), |
| 651 | AT_default_value_string = (0x01e0|FORM_STRING), |
| 652 | AT_friends = (0x01f0|FORM_BLOCK2), |
| 653 | AT_inline = (0x0200|FORM_STRING), |
| 654 | AT_is_optional = (0x0210|FORM_STRING), |
| 655 | AT_lower_bound_ref = (0x0220|FORM_REF), |
| 656 | AT_lower_bound_data2 = (0x0220|FORM_DATA2), |
| 657 | AT_lower_bound_data4 = (0x0220|FORM_DATA4), |
| 658 | AT_lower_bound_data8 = (0x0220|FORM_DATA8), |
| 659 | AT_private = (0x0240|FORM_STRING), |
| 660 | AT_producer = (0x0250|FORM_STRING), |
| 661 | AT_program = (0x0230|FORM_STRING), |
| 662 | AT_protected = (0x0260|FORM_STRING), |
| 663 | AT_prototyped = (0x0270|FORM_STRING), |
| 664 | AT_public = (0x0280|FORM_STRING), |
| 665 | AT_pure_virtual = (0x0290|FORM_STRING), |
| 666 | AT_return_addr = (0x02a0|FORM_BLOCK2), |
| 667 | AT_abstract_origin = (0x02b0|FORM_REF), |
| 668 | AT_start_scope = (0x02c0|FORM_DATA4), |
| 669 | AT_stride_size = (0x02e0|FORM_DATA4), |
| 670 | AT_upper_bound_ref = (0x02f0|FORM_REF), |
| 671 | AT_upper_bound_data2 = (0x02f0|FORM_DATA2), |
| 672 | AT_upper_bound_data4 = (0x02f0|FORM_DATA4), |
| 673 | AT_upper_bound_data8 = (0x02f0|FORM_DATA8), |
| 674 | AT_virtual = (0x0300|FORM_STRING), |
| 675 | |
| 676 | /* GNU extensions. */ |
| 677 | |
| 678 | AT_sf_names = (0x8000|FORM_DATA4), |
| 679 | AT_src_info = (0x8010|FORM_DATA4), |
| 680 | AT_mac_info = (0x8020|FORM_DATA4), |
| 681 | AT_src_coords = (0x8030|FORM_DATA4), |
| 682 | AT_body_begin = (0x8040|FORM_ADDR), |
| 683 | AT_body_end = (0x8050|FORM_ADDR) |
| 684 | }; |
| 685 | |
| 686 | /* end of enums taken from gdb-6.0 sources */ |
| 687 | |
| 688 | void VG_(read_debuginfo_dwarf1) ( |
| 689 | SegInfo* si, |
| 690 | UChar* dwarf1d, Int dwarf1d_sz, |
| 691 | UChar* dwarf1l, Int dwarf1l_sz ) |
| 692 | { |
| 693 | UInt stmt_list; |
| 694 | Bool stmt_list_found; |
| 695 | Int die_offset, die_szb, at_offset; |
| 696 | UShort die_kind, at_kind; |
| 697 | UChar* at_base; |
| 698 | UChar* src_filename; |
| 699 | |
| 700 | if (0) |
| 701 | VG_(printf)("read_debuginfo_dwarf1 ( %p, %d, %p, %d )\n", |
| 702 | dwarf1d, dwarf1d_sz, dwarf1l, dwarf1l_sz ); |
| 703 | |
| 704 | /* This loop scans the DIEs. */ |
| 705 | die_offset = 0; |
| 706 | while (True) { |
| 707 | if (die_offset >= dwarf1d_sz) break; |
| 708 | |
| 709 | die_szb = *(Int*)(dwarf1d + die_offset); |
| 710 | die_kind = *(UShort*)(dwarf1d + die_offset + 4); |
| 711 | |
| 712 | /* We're only interested in compile_unit DIEs; ignore others. */ |
| 713 | if (die_kind != TAG_compile_unit) { |
| 714 | die_offset += die_szb; |
| 715 | continue; |
| 716 | } |
| 717 | |
| 718 | if (0) |
| 719 | VG_(printf)("compile-unit DIE: offset %d, tag 0x%x, size %d\n", |
| 720 | die_offset, (Int)die_kind, die_szb ); |
| 721 | |
| 722 | /* We've got a compile_unit DIE starting at (dwarf1d + |
| 723 | die_offset+6). Try and find the AT_name and AT_stmt_list |
| 724 | attributes. Then, finally, we can read the line number info |
| 725 | for this source file. */ |
| 726 | |
| 727 | /* The next 3 are set as we find the relevant attrs. */ |
| 728 | src_filename = NULL; |
| 729 | stmt_list_found = False; |
| 730 | stmt_list = 0; |
| 731 | |
| 732 | /* This loop scans the Attrs inside compile_unit DIEs. */ |
| 733 | at_base = dwarf1d + die_offset + 6; |
| 734 | at_offset = 0; |
| 735 | while (True) { |
| 736 | if (at_offset >= die_szb-6) break; |
| 737 | |
| 738 | at_kind = *(UShort*)(at_base + at_offset); |
| 739 | if (0) VG_(printf)("atoffset %d, attag 0x%x\n", |
| 740 | at_offset, (Int)at_kind ); |
| 741 | at_offset += 2; /* step over the attribute itself */ |
| 742 | /* We have to examine the attribute to figure out its |
| 743 | length. */ |
| 744 | switch (at_kind) { |
| 745 | case AT_stmt_list: |
| 746 | case AT_language: |
| 747 | case AT_sibling: |
| 748 | if (at_kind == AT_stmt_list) { |
| 749 | stmt_list_found = True; |
| 750 | stmt_list = *(Int*)(at_base+at_offset); |
| 751 | } |
| 752 | at_offset += 4; break; |
| 753 | case AT_high_pc: |
| 754 | case AT_low_pc: |
| 755 | at_offset += sizeof(void*); break; |
| 756 | case AT_name: |
| 757 | case AT_producer: |
| 758 | case AT_comp_dir: |
| 759 | /* Zero terminated string, step over it. */ |
| 760 | if (at_kind == AT_name) |
| 761 | src_filename = at_base + at_offset; |
| 762 | while (at_offset < die_szb-6 && at_base[at_offset] != 0) |
| 763 | at_offset++; |
| 764 | at_offset++; |
| 765 | break; |
| 766 | default: |
| 767 | VG_(printf)("Unhandled DWARF-1 attribute 0x%x\n", |
| 768 | (Int)at_kind ); |
| 769 | VG_(core_panic)("Unhandled DWARF-1 attribute"); |
| 770 | } /* switch (at_kind) */ |
| 771 | } /* looping over attributes */ |
| 772 | |
| 773 | /* So, did we find the required stuff for a line number table in |
| 774 | this DIE? If yes, read it. */ |
| 775 | if (stmt_list_found /* there is a line number table */ |
| 776 | && src_filename != NULL /* we know the source filename */ |
| 777 | ) { |
| 778 | /* Table starts: |
| 779 | Length: |
| 780 | 4 bytes, includes the entire table |
| 781 | Base address: |
| 782 | unclear (4? 8?), assuming native pointer size here. |
| 783 | Then a sequence of triples |
| 784 | (source line number -- 32 bits |
| 785 | source line column -- 16 bits |
| 786 | address delta -- 32 bits) |
| 787 | */ |
| 788 | Addr base; |
| 789 | Int len; |
| 790 | Char* curr_filenm; |
| 791 | UChar* ptr; |
| 792 | UInt prev_line, prev_delta; |
| 793 | |
| 794 | curr_filenm = VG_(addStr) ( si, src_filename, -1 ); |
| 795 | prev_line = prev_delta = 0; |
| 796 | |
| 797 | ptr = dwarf1l + stmt_list; |
| 798 | len = *(Int*)ptr; ptr += sizeof(Int); |
| 799 | base = (Addr)(*(void**)ptr); ptr += sizeof(void*); |
| 800 | len -= (sizeof(Int) + sizeof(void*)); |
| 801 | while (len > 0) { |
| 802 | UInt line; |
| 803 | UShort col; |
| 804 | UInt delta; |
| 805 | line = *(UInt*)ptr; ptr += sizeof(UInt); |
| 806 | col = *(UShort*)ptr; ptr += sizeof(UShort); |
| 807 | delta = *(UShort*)ptr; ptr += sizeof(UInt); |
| 808 | if (0) VG_(printf)("line %d, col %d, delta %d\n", |
| 809 | line, (Int)col, delta ); |
| 810 | len -= (sizeof(UInt) + sizeof(UShort) + sizeof(UInt)); |
| 811 | |
| 812 | if (delta > 0 && prev_line > 0) { |
| 813 | if (0) VG_(printf) (" %d %d-%d\n", |
| 814 | prev_line, prev_delta, delta-1); |
| 815 | VG_(addLineInfo) ( si, curr_filenm, |
| 816 | base + prev_delta, base + delta, |
| 817 | prev_line, 0 ); |
| 818 | } |
| 819 | prev_line = line; |
| 820 | prev_delta = delta; |
| 821 | } |
| 822 | } |
| 823 | |
| 824 | /* Move on the the next DIE. */ |
| 825 | die_offset += die_szb; |
| 826 | |
| 827 | } /* Looping over DIEs */ |
| 828 | |
| 829 | } |
| 830 | |
| 831 | |
njn | 4bbdc97 | 2003-10-16 10:10:55 +0000 | [diff] [blame] | 832 | /*--------------------------------------------------------------------*/ |
jseward | 8b3131a | 2003-12-13 23:16:26 +0000 | [diff] [blame] | 833 | /*--- end vg_dwarf.c ---*/ |
njn | 4bbdc97 | 2003-10-16 10:10:55 +0000 | [diff] [blame] | 834 | /*--------------------------------------------------------------------*/ |