1 /* Return line number information of CU. 2 Copyright (C) 2004 Red Hat, Inc. 3 Written by Ulrich Drepper <drepper (at) redhat.com>, 2004. 4 5 This program is Open Source software; you can redistribute it and/or 6 modify it under the terms of the Open Software License version 1.0 as 7 published by the Open Source Initiative. 8 9 You should have received a copy of the Open Software License along 10 with this program; if not, you may obtain a copy of the Open Software 11 License version 1.0 from http://www.opensource.org/licenses/osl.php or 12 by writing the Open Source Initiative c/o Lawrence Rosen, Esq., 13 3001 King Ranch Road, Ukiah, CA 95482. */ 14 15 #ifdef HAVE_CONFIG_H 16 # include <config.h> 17 #endif 18 19 #include <assert.h> 20 #include <stdlib.h> 21 #include <string.h> 22 #include "dwarf.h" 23 #include "libdwP.h" 24 25 26 struct filelist 27 { 28 Dwarf_Fileinfo info; 29 struct filelist *next; 30 }; 31 32 struct linelist 33 { 34 Dwarf_Line line; 35 struct linelist *next; 36 }; 37 38 39 /* Adds a new line to the matrix. We cannot definte a function because 40 we want to use alloca. */ 41 #define NEW_LINE(end_seq) \ 42 do { \ 43 /* Add the new line. */ \ 44 new_line = (struct linelist *) alloca (sizeof (struct linelist)); \ 45 \ 46 /* Set the line information. */ \ 47 new_line->line.addr = address; \ 48 new_line->line.file = file; \ 49 new_line->line.line = line; \ 50 new_line->line.column = column; \ 51 new_line->line.is_stmt = is_stmt; \ 52 new_line->line.basic_block = basic_block; \ 53 new_line->line.end_sequence = end_seq; \ 54 new_line->line.prologue_end = prologue_end; \ 55 new_line->line.epilogue_begin = epilogue_begin; \ 56 \ 57 new_line->next = linelist; \ 58 linelist = new_line; \ 59 ++nlinelist; \ 60 } while (0) 61 62 63 int 64 dwarf_getsrclines (Dwarf_Die *cudie, Dwarf_Lines **lines, size_t *nlines) 65 { 66 if (unlikely (cudie == NULL || dwarf_tag (cudie) != DW_TAG_compile_unit)) 67 return -1; 68 69 int res = -1; 70 71 /* Get the information if it is not already known. */ 72 struct Dwarf_CU *const cu = cudie->cu; 73 if (cu->lines == NULL) 74 { 75 /* Failsafe mode: no data found. */ 76 cu->lines = (void *) -1l; 77 cu->files = (void *) -1l; 78 79 /* The die must have a statement list associated. */ 80 Dwarf_Attribute stmt_list_mem; 81 Dwarf_Attribute *stmt_list = dwarf_attr (cudie, DW_AT_stmt_list, 82 &stmt_list_mem); 83 84 /* Get the offset into the .debug_line section. NB: this call 85 also checks whether the previous dwarf_attr call failed. */ 86 Dwarf_Word offset; 87 if (dwarf_formudata (stmt_list, &offset) != 0) 88 goto out; 89 90 Dwarf *dbg = cu->dbg; 91 if (dbg->sectiondata[IDX_debug_line] == NULL) 92 { 93 __libdw_seterrno (DWARF_E_NO_DEBUG_LINE); 94 goto out; 95 } 96 uint8_t *linep = dbg->sectiondata[IDX_debug_line]->d_buf + offset; 97 uint8_t *lineendp = (dbg->sectiondata[IDX_debug_line]->d_buf 98 + dbg->sectiondata[IDX_debug_line]->d_size); 99 100 /* Get the compilation directory. */ 101 Dwarf_Attribute compdir_attr_mem; 102 Dwarf_Attribute *compdir_attr = dwarf_attr (cudie, DW_AT_comp_dir, 103 &compdir_attr_mem); 104 const char *comp_dir = dwarf_formstring (compdir_attr); 105 106 if (unlikely (linep + 4 > lineendp)) 107 { 108 invalid_data: 109 __libdw_seterrno (DWARF_E_INVALID_DEBUG_LINE); 110 goto out; 111 } 112 Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, linep); 113 unsigned int length = 4; 114 if (unlikely (unit_length == 0xffffffff)) 115 { 116 if (unlikely (linep + 8 > lineendp)) 117 goto invalid_data; 118 unit_length = read_8ubyte_unaligned_inc (dbg, linep); 119 length = 8; 120 } 121 122 /* Check whether we have enough room in the section. */ 123 if (unit_length < 2 + length + 5 * 1 124 || unlikely (linep + unit_length > lineendp)) 125 goto invalid_data; 126 lineendp = linep + unit_length; 127 128 /* The next element of the header is the version identifier. */ 129 uint_fast16_t version = read_2ubyte_unaligned_inc (dbg, linep); 130 if (unlikely (version != DWARF_VERSION)) 131 { 132 __libdw_seterrno (DWARF_E_VERSION); 133 goto out; 134 } 135 136 /* Next comes the header length. */ 137 Dwarf_Word header_length; 138 if (length == 4) 139 header_length = read_4ubyte_unaligned_inc (dbg, linep); 140 else 141 header_length = read_8ubyte_unaligned_inc (dbg, linep); 142 unsigned char *header_start = linep; 143 144 /* Next the minimum instruction length. */ 145 uint_fast8_t minimum_instr_len = *linep++; 146 147 /* Then the flag determining the default value of the is_stmt 148 register. */ 149 uint_fast8_t default_is_stmt = *linep++; 150 151 /* Now the line base. */ 152 int_fast8_t line_base = *((int_fast8_t *) linep); 153 ++linep; 154 155 /* And the line range. */ 156 uint_fast8_t line_range = *linep++; 157 158 /* The opcode base. */ 159 uint_fast8_t opcode_base = *linep++; 160 161 /* Remember array with the standard opcode length (-1 to account for 162 the opcode with value zero not being mentioned). */ 163 uint8_t *standard_opcode_lengths = linep - 1; 164 linep += opcode_base - 1; 165 if (unlikely (linep >= lineendp)) 166 goto invalid_data; 167 168 /* First comes the list of directories. Add the compilation 169 directory first since the index zero is used for it. */ 170 struct dirlist 171 { 172 const char *dir; 173 size_t len; 174 struct dirlist *next; 175 } comp_dir_elem = 176 { 177 .dir = comp_dir, 178 .len = comp_dir ? strlen (comp_dir) : 0, 179 .next = NULL 180 }; 181 struct dirlist *dirlist = &comp_dir_elem; 182 unsigned int ndirlist = 1; 183 184 // XXX Directly construct array to conserve memory? 185 while (*linep != 0) 186 { 187 struct dirlist *new_dir = 188 (struct dirlist *) alloca (sizeof (*new_dir)); 189 190 new_dir->dir = (char *) linep; 191 uint8_t *endp = memchr (linep, '\0', lineendp - linep); 192 if (endp == NULL) 193 goto invalid_data; 194 new_dir->len = endp - linep; 195 new_dir->next = dirlist; 196 dirlist = new_dir; 197 ++ndirlist; 198 linep = endp + 1; 199 } 200 /* Skip the final NUL byte. */ 201 ++linep; 202 203 /* Rearrange the list in array form. */ 204 struct dirlist **dirarray 205 = (struct dirlist **) alloca (ndirlist * sizeof (*dirarray)); 206 while (ndirlist-- > 0) 207 { 208 dirarray[ndirlist] = dirlist; 209 dirlist = dirlist->next; 210 } 211 212 /* Now read the files. */ 213 struct filelist null_file = 214 { 215 .info = 216 { 217 .name = "???", 218 .mtime = 0, 219 .length = 0 220 }, 221 .next = NULL 222 }; 223 struct filelist *filelist = &null_file; 224 unsigned int nfilelist = 1; 225 226 if (unlikely (linep >= lineendp)) 227 goto invalid_data; 228 while (*linep != 0) 229 { 230 struct filelist *new_file = 231 (struct filelist *) alloca (sizeof (*new_file)); 232 233 /* First comes the file name. */ 234 char *fname = (char *) linep; 235 uint8_t *endp = memchr (fname, '\0', lineendp - linep); 236 if (endp == NULL) 237 goto invalid_data; 238 size_t fnamelen = endp - (uint8_t *) fname; 239 linep = endp + 1; 240 241 /* Then the index. */ 242 Dwarf_Word diridx; 243 get_uleb128 (diridx, linep); 244 if (unlikely (diridx >= ndirlist)) 245 { 246 __libdw_seterrno (DWARF_E_INVALID_DIR_IDX); 247 goto out; 248 } 249 250 if (*fname == '/') 251 /* It's an absolute path. */ 252 new_file->info.name = fname; 253 else 254 { 255 new_file->info.name = libdw_alloc (dbg, char, 1, 256 dirarray[diridx]->len + 1 257 + fnamelen + 1); 258 char *cp = new_file->info.name; 259 260 if (dirarray[diridx]->dir != NULL) 261 { 262 /* This value could be NULL in case the DW_AT_comp_dir 263 was not present. We cannot do much in this case. 264 The easiest thing is to convert the path in an 265 absolute path. */ 266 cp = stpcpy (cp, dirarray[diridx]->dir); 267 } 268 *cp++ = '/'; 269 strcpy (cp, fname); 270 assert (strlen (new_file->info.name) 271 < dirarray[diridx]->len + 1 + fnamelen + 1); 272 } 273 274 /* Next comes the modification time. */ 275 get_uleb128 (new_file->info.mtime, linep); 276 277 /* Finally the length of the file. */ 278 get_uleb128 (new_file->info.length, linep); 279 280 new_file->next = filelist; 281 filelist = new_file; 282 ++nfilelist; 283 } 284 /* Skip the final NUL byte. */ 285 ++linep; 286 287 /* Consistency check. */ 288 if (unlikely (linep != header_start + header_length)) 289 { 290 __libdw_seterrno (DWARF_E_INVALID_DWARF); 291 goto out; 292 } 293 294 /* We are about to process the statement program. Initialize the 295 state machine registers (see 6.2.2 in the v2.1 specification). */ 296 Dwarf_Word address = 0; 297 size_t file = 1; 298 size_t line = 1; 299 size_t column = 0; 300 uint_fast8_t is_stmt = default_is_stmt; 301 int basic_block = 0; 302 int prologue_end = 0; 303 int epilogue_begin = 0; 304 305 /* Process the instructions. */ 306 struct linelist *linelist = NULL; 307 unsigned int nlinelist = 0; 308 while (linep < lineendp) 309 { 310 struct linelist *new_line; 311 unsigned int opcode; 312 unsigned int u128; 313 int s128; 314 315 /* Read the opcode. */ 316 opcode = *linep++; 317 318 /* Is this a special opcode? */ 319 if (likely (opcode >= opcode_base)) 320 { 321 /* Yes. Handling this is quite easy since the opcode value 322 is computed with 323 324 opcode = (desired line increment - line_base) 325 + (line_range * address advance) + opcode_base 326 */ 327 int line_increment = (line_base 328 + (opcode - opcode_base) % line_range); 329 unsigned int address_increment = (minimum_instr_len 330 * ((opcode - opcode_base) 331 / line_range)); 332 333 /* Perform the increments. */ 334 line += line_increment; 335 address += address_increment; 336 337 /* Add a new line with the current state machine values. */ 338 NEW_LINE (0); 339 340 /* Reset the flags. */ 341 basic_block = 0; 342 prologue_end = 0; 343 epilogue_begin = 0; 344 } 345 else if (opcode == 0) 346 { 347 /* This an extended opcode. */ 348 if (unlikely (linep + 2 > lineendp)) 349 goto invalid_data; 350 351 /* The length. */ 352 unsigned int len = *linep++; 353 354 if (unlikely (linep + len > lineendp)) 355 goto invalid_data; 356 357 /* The sub-opcode. */ 358 opcode = *linep++; 359 360 switch (opcode) 361 { 362 case DW_LNE_end_sequence: 363 /* Add a new line with the current state machine values. 364 The is the end of the sequence. */ 365 NEW_LINE (1); 366 367 /* Reset the registers. */ 368 address = 0; 369 file = 1; 370 line = 1; 371 column = 0; 372 is_stmt = default_is_stmt; 373 basic_block = 0; 374 prologue_end = 0; 375 epilogue_begin = 0; 376 break; 377 378 case DW_LNE_set_address: 379 /* The value is an address. The size is defined as 380 apporiate for the target machine. We use the 381 address size field from the CU header. */ 382 if (cu->address_size == 4) 383 address = read_4ubyte_unaligned_inc (dbg, linep); 384 else 385 address = read_8ubyte_unaligned_inc (dbg, linep); 386 break; 387 388 case DW_LNE_define_file: 389 { 390 char *fname = (char *) linep; 391 uint8_t *endp = memchr (linep, '\0', lineendp - linep); 392 if (endp == NULL) 393 goto invalid_data; 394 size_t fnamelen = endp - linep; 395 linep = endp + 1; 396 397 unsigned int diridx; 398 get_uleb128 (diridx, linep); 399 Dwarf_Word mtime; 400 get_uleb128 (mtime, linep); 401 Dwarf_Word filelength; 402 get_uleb128 (filelength, linep); 403 404 struct filelist *new_file = 405 (struct filelist *) alloca (sizeof (*new_file)); 406 if (fname[0] == '/') 407 new_file->info.name = fname; 408 else 409 { 410 new_file->info.name = 411 libdw_alloc (dbg, char, 1, (dirarray[diridx]->len + 1 412 + fnamelen + 1)); 413 char *cp = new_file->info.name; 414 415 if (dirarray[diridx]->dir != NULL) 416 /* This value could be NULL in case the 417 DW_AT_comp_dir was not present. We 418 cannot do much in this case. The easiest 419 thing is to convert the path in an 420 absolute path. */ 421 cp = stpcpy (cp, dirarray[diridx]->dir); 422 *cp++ = '/'; 423 strcpy (cp, fname); 424 } 425 426 new_file->info.mtime = mtime; 427 new_file->info.length = filelength; 428 new_file->next = filelist; 429 filelist = new_file; 430 ++nfilelist; 431 } 432 break; 433 434 default: 435 /* Unknown, ignore it. */ 436 linep += len - 1; 437 break; 438 } 439 } 440 else if (opcode <= DW_LNS_set_epilog_begin) 441 { 442 /* This is a known standard opcode. */ 443 switch (opcode) 444 { 445 case DW_LNS_copy: 446 /* Takes no argument. */ 447 if (unlikely (standard_opcode_lengths[opcode] != 0)) 448 goto invalid_data; 449 450 /* Add a new line with the current state machine values. */ 451 NEW_LINE (0); 452 453 /* Reset the flags. */ 454 basic_block = 0; 455 /* XXX Whether the following two lines are necessary is 456 unclear. I guess the current v2.1 specification has 457 a bug in that it says clearing these two registers is 458 not necessary. */ 459 prologue_end = 0; 460 epilogue_begin = 0; 461 break; 462 463 case DW_LNS_advance_pc: 464 /* Takes one uleb128 parameter which is added to the 465 address. */ 466 if (unlikely (standard_opcode_lengths[opcode] != 1)) 467 goto invalid_data; 468 469 get_uleb128 (u128, linep); 470 address += minimum_instr_len * u128; 471 break; 472 473 case DW_LNS_advance_line: 474 /* Takes one sleb128 parameter which is added to the 475 line. */ 476 if (unlikely (standard_opcode_lengths[opcode] != 1)) 477 goto invalid_data; 478 479 get_sleb128 (s128, linep); 480 line += s128; 481 break; 482 483 case DW_LNS_set_file: 484 /* Takes one uleb128 parameter which is stored in file. */ 485 if (unlikely (standard_opcode_lengths[opcode] != 1)) 486 goto invalid_data; 487 488 get_uleb128 (u128, linep); 489 file = u128; 490 break; 491 492 case DW_LNS_set_column: 493 /* Takes one uleb128 parameter which is stored in column. */ 494 if (unlikely (standard_opcode_lengths[opcode] != 1)) 495 goto invalid_data; 496 497 get_uleb128 (u128, linep); 498 column = u128; 499 break; 500 501 case DW_LNS_negate_stmt: 502 /* Takes no argument. */ 503 if (unlikely (standard_opcode_lengths[opcode] != 0)) 504 goto invalid_data; 505 506 is_stmt = 1 - is_stmt; 507 break; 508 509 case DW_LNS_set_basic_block: 510 /* Takes no argument. */ 511 if (unlikely (standard_opcode_lengths[opcode] != 0)) 512 goto invalid_data; 513 514 basic_block = 1; 515 break; 516 517 case DW_LNS_const_add_pc: 518 /* Takes no argument. */ 519 if (unlikely (standard_opcode_lengths[opcode] != 0)) 520 goto invalid_data; 521 522 address += (minimum_instr_len 523 * ((255 - opcode_base) / line_range)); 524 break; 525 526 case DW_LNS_fixed_advance_pc: 527 /* Takes one 16 bit parameter which is added to the 528 address. */ 529 if (unlikely (standard_opcode_lengths[opcode] != 1)) 530 goto invalid_data; 531 532 address += read_2ubyte_unaligned_inc (dbg, linep); 533 break; 534 535 case DW_LNS_set_prologue_end: 536 /* Takes no argument. */ 537 if (unlikely (standard_opcode_lengths[opcode] != 0)) 538 goto invalid_data; 539 540 prologue_end = 1; 541 break; 542 543 case DW_LNS_set_epilog_begin: 544 /* Takes no argument. */ 545 if (unlikely (standard_opcode_lengths[opcode] != 0)) 546 goto invalid_data; 547 548 epilogue_begin = 1; 549 break; 550 } 551 } 552 else 553 { 554 /* This is a new opcode the generator but not we know about. 555 Read the parameters associated with it but then discard 556 everything. Read all the parameters for this opcode. */ 557 for (int n = standard_opcode_lengths[opcode]; n > 0; --n) 558 get_uleb128 (u128, linep); 559 560 /* Next round, ignore this opcode. */ 561 continue; 562 } 563 } 564 565 /* Put all the files in an array. */ 566 Dwarf_Files *files = libdw_alloc (dbg, Dwarf_Files, 567 sizeof (Dwarf_Files) 568 + nfilelist * sizeof (Dwarf_Fileinfo), 569 1); 570 files->nfiles = nfilelist; 571 while (nfilelist-- > 0) 572 { 573 files->info[nfilelist] = filelist->info; 574 filelist = filelist->next; 575 } 576 assert (filelist == NULL); 577 578 /* Remember the debugging descriptor. */ 579 files->dbg = dbg; 580 581 /* Make the file data structure available through the CU. */ 582 cu->files = files; 583 584 cu->lines = libdw_alloc (dbg, Dwarf_Lines, (sizeof (Dwarf_Lines) 585 + (sizeof (Dwarf_Line) 586 * nlinelist)), 1); 587 cu->lines->nlines = nlinelist; 588 while (nlinelist-- > 0) 589 { 590 cu->lines->info[nlinelist] = linelist->line; 591 cu->lines->info[nlinelist].files = files; 592 linelist = linelist->next; 593 } 594 assert (linelist == NULL); 595 596 /* Success. */ 597 res = 0; 598 } 599 else if (cu->lines != (void *) -1l) 600 /* We already have the information. */ 601 res = 0; 602 603 if (likely (res == 0)) 604 { 605 *lines = cu->lines; 606 *nlines = cu->lines->nlines; 607 } 608 out: 609 610 // XXX Eventually: unlocking here. 611 612 return res; 613 } 614