1 /* 2 Copyright (c) 2019-2020, David Anderson 3 All rights reserved. 4 5 Redistribution and use in source and binary forms, with 6 or without modification, are permitted provided that the 7 following conditions are met: 8 9 Redistributions of source code must retain the above 10 copyright notice, this list of conditions and the following 11 disclaimer. 12 13 Redistributions in binary form must reproduce the above 14 copyright notice, this list of conditions and the following 15 disclaimer in the documentation and/or other materials 16 provided with the distribution. 17 18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 19 CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 20 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 23 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 29 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 30 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 31 32 #include "config.h" 33 #include <stdio.h> 34 #ifdef HAVE_MALLOC_H 35 #include <malloc.h> 36 #endif /* HAVE_MALLOC_H */ 37 #ifdef HAVE_STDDEF_H 38 #include <stddef.h> /* ptrdiff_t */ 39 #endif /* HAVE_STDDEF_H */ 40 #ifdef HAVE_STDLIB_H 41 #include <stdlib.h> 42 #endif /* HAVE_STDLIB_H */ 43 #include <string.h> 44 #ifdef HAVE_ELF_H 45 #include <elf.h> 46 #endif /* HAVE_ELF_H */ 47 #ifdef HAVE_UNISTD_H 48 #include <unistd.h> /* getcwd */ 49 #endif /* HAVE_UNISTD_H */ 50 #if 0 51 #include <sys/types.h> /* for open() */ 52 #include <sys/stat.h> /* for open() */ 53 #include <fcntl.h> /* for open() */ 54 #include <errno.h> 55 #endif 56 #include "dwarf_incl.h" 57 #include "dwarf_alloc.h" 58 #include "dwarf_error.h" 59 #include "dwarf_util.h" 60 #include "dwarfstring.h" 61 #include "dwarf_debuglink.h" 62 63 #ifndef O_BINARY 64 #define O_BINARY 0 65 #endif /* O_BINARY */ 66 67 #define MINBUFLEN 1000 68 #define TRUE 1 69 #define FALSE 0 70 71 #ifdef HAVE_UNUSED_ATTRIBUTE 72 #define UNUSEDARG __attribute__ ((unused)) 73 #else 74 #define UNUSEDARG 75 #endif 76 77 78 #if _WIN32 79 #define NULL_DEVICE_NAME "NUL" 80 #else 81 #define NULL_DEVICE_NAME "/dev/null" 82 #endif /* _WIN32 */ 83 84 #ifdef WORDS_BIGENDIAN 85 #define ASNAR(func,t,s) \ 86 do { \ 87 unsigned tbyte = sizeof(t) - sizeof(s); \ 88 t = 0; \ 89 func(((char *)&t)+tbyte ,&s[0],sizeof(s)); \ 90 } while (0) 91 #else /* LITTLE ENDIAN */ 92 #define ASNAR(func,t,s) \ 93 do { \ 94 t = 0; \ 95 func(&t,&s[0],sizeof(s)); \ 96 } while (0) 97 #endif /* end LITTLE- BIG-ENDIAN */ 98 99 static int 100 extract_buildid(Dwarf_Debug dbg, 101 struct Dwarf_Section_s * pbuildid, 102 unsigned *type_returned, 103 char **owner_name_returned, 104 unsigned char **build_id_returned, 105 unsigned *build_id_length_returned, 106 Dwarf_Error *error); 107 108 struct joins_s { 109 char * js_fullpath; 110 dwarfstring js_dirname; 111 dwarfstring js_basepath; 112 dwarfstring js_basename; 113 dwarfstring js_cwd; 114 dwarfstring js_originalfullpath; 115 dwarfstring js_tmp; 116 dwarfstring js_tmp2; 117 dwarfstring js_tmpdeb; 118 dwarfstring js_tmp3; 119 dwarfstring js_buildid; 120 dwarfstring js_buildid_filename; 121 }; 122 123 #if 0 124 int 125 _dwarf_check_string_valid( 126 void *areaptr, 127 void *strptr, 128 void *areaendptr, 129 int suggested_error, 130 int *errcode) 131 { 132 Dwarf_Small *start = areaptr; 133 Dwarf_Small *p = strptr; 134 Dwarf_Small *end = areaendptr; 135 ptrdiff_t diff = 0; 136 137 if (p < start) { 138 diff = start - p; 139 #ifdef TESTING 140 printf("Error string start pointer error: loc %" 141 DW_PR_DSs 142 " bytes before available area \n",(Dwarf_Signed)diff); 143 #endif /* TESTING */ 144 *errcode = suggested_error; 145 return DW_DLV_ERROR; 146 } 147 if (p >= end) { 148 diff = p - start; 149 #ifdef TESTING 150 printf("Error string end pointer error, not terminated %" 151 " before end of area. Length: " 152 DW_PR_DSs "\n",(Dwarf_Signed)diff); 153 #endif /* TESTING */ 154 *errcode = suggested_error; 155 return DW_DLV_ERROR; 156 } 157 while (p < end) { 158 if (*p == 0) { 159 return DW_DLV_OK; 160 } 161 ++p; 162 } 163 diff = p - start; 164 #ifdef TESTING 165 printf("Error string not terminated error: not ended after %" 166 DW_PR_DSs " bytes (past end of available bytes)\n", 167 (Dwarf_Signed)diff); 168 #endif /* TESTING */ 169 *errcode = DW_DLE_STRING_NOT_TERMINATED; 170 return DW_DLV_ERROR; 171 } 172 #endif 173 174 175 #if 0 176 static int 177 does_file_exist(char *f) 178 { 179 int fd = 0; 180 181 fd = open(f,O_RDONLY|O_BINARY); 182 if (fd < 0) { 183 return DW_DLV_NO_ENTRY; 184 } 185 /* Here we could derive the crc to validate the file. */ 186 close(fd); 187 return DW_DLV_OK; 188 } 189 #endif 190 191 192 static void 193 construct_js(struct joins_s * js) 194 { 195 memset(js,0,sizeof(struct joins_s)); 196 dwarfstring_constructor(&js->js_basename); 197 dwarfstring_constructor(&js->js_dirname); 198 dwarfstring_constructor(&js->js_basepath); 199 dwarfstring_constructor(&js->js_cwd); 200 dwarfstring_constructor(&js->js_originalfullpath); 201 dwarfstring_constructor(&js->js_tmp); 202 dwarfstring_constructor(&js->js_tmp2); 203 dwarfstring_constructor(&js->js_tmpdeb); 204 dwarfstring_constructor(&js->js_tmp3); 205 dwarfstring_constructor(&js->js_buildid); 206 dwarfstring_constructor(&js->js_buildid_filename); 207 } 208 static void 209 destruct_js(struct joins_s * js) 210 { 211 dwarfstring_destructor(&js->js_dirname); 212 dwarfstring_destructor(&js->js_basepath); 213 dwarfstring_destructor(&js->js_basename); 214 dwarfstring_destructor(&js->js_cwd); 215 dwarfstring_destructor(&js->js_originalfullpath); 216 dwarfstring_destructor(&js->js_tmp); 217 dwarfstring_destructor(&js->js_tmp2); 218 dwarfstring_destructor(&js->js_tmpdeb); 219 dwarfstring_destructor(&js->js_tmp3); 220 dwarfstring_destructor(&js->js_buildid); 221 dwarfstring_destructor(&js->js_buildid_filename); 222 } 223 224 static char joinchar = '/'; 225 static char* joinstr = "/"; 226 227 int 228 _dwarf_pathjoinl(dwarfstring *target,dwarfstring * input) 229 { 230 char *inputs = dwarfstring_string(input); 231 char *targ = dwarfstring_string(target); 232 size_t targlen = 0; 233 234 if (!dwarfstring_strlen(target)) { 235 dwarfstring_append(target,dwarfstring_string(input)); 236 return DW_DLV_OK; 237 } 238 targlen = dwarfstring_strlen(target); 239 targ = dwarfstring_string(target); 240 if (targ[targlen-1] != joinchar) { 241 if (*inputs != joinchar) { 242 dwarfstring_append(target,joinstr); 243 dwarfstring_append(target,inputs); 244 } else { 245 dwarfstring_append(target,inputs); 246 } 247 } else { 248 if (*inputs != joinchar) { 249 dwarfstring_append(target,inputs); 250 } else { 251 dwarfstring_append(target,inputs+1); 252 } 253 } 254 return DW_DLV_OK; 255 } 256 /* ASSERT: the last character in s is not a / */ 257 static size_t 258 mydirlen(char *s) 259 { 260 char *cp = 0; 261 char *lastjoinchar = 0; 262 size_t count =0; 263 264 for(cp = s ; *cp ; ++cp,++count) { 265 if (*cp == joinchar) { 266 lastjoinchar = cp; 267 } 268 } 269 if (lastjoinchar) { 270 /* we know diff is postive in all cases */ 271 ptrdiff_t diff = lastjoinchar - s; 272 /* count the last join as mydirlen. */ 273 return (size_t)(diff+1); 274 } 275 return 0; 276 } 277 278 struct dwarfstring_list_s { 279 dwarfstring dl_string; 280 struct dwarfstring_list_s *dl_next; 281 }; 282 283 static void 284 dwarfstring_list_constructor(struct dwarfstring_list_s *l) 285 { 286 dwarfstring_constructor(&l->dl_string); 287 l->dl_next = 0; 288 } 289 290 static int 291 dwarfstring_list_add_new(struct dwarfstring_list_s * base_entry, 292 struct dwarfstring_list_s *prev, 293 dwarfstring * input, 294 struct dwarfstring_list_s ** new_out, 295 int *errcode) 296 { 297 struct dwarfstring_list_s *next = 0; 298 if(prev) { 299 next = ( struct dwarfstring_list_s *) 300 malloc(sizeof(struct dwarfstring_list_s)); 301 if (!next) { 302 *errcode = DW_DLE_ALLOC_FAIL; 303 return DW_DLV_ERROR; 304 } 305 dwarfstring_list_constructor(next); 306 } else { 307 next = base_entry; 308 } 309 dwarfstring_append(&next->dl_string, 310 dwarfstring_string(input)); 311 if (prev) { 312 prev->dl_next = next; 313 } 314 *new_out = next; 315 return DW_DLV_OK; 316 } 317 318 /* destructs passed in entry (does not free it) and all 319 those on the dl_next list (those are freed). */ 320 static void 321 dwarfstring_list_destructor(struct dwarfstring_list_s *l) 322 { 323 struct dwarfstring_list_s *curl = l; 324 struct dwarfstring_list_s *nextl = l; 325 326 nextl = curl->dl_next; 327 dwarfstring_destructor(&curl->dl_string); 328 curl->dl_next = 0; 329 curl = nextl; 330 for( ; curl ; curl = nextl) { 331 nextl = curl->dl_next; 332 dwarfstring_destructor(&curl->dl_string); 333 curl->dl_next = 0; 334 free(curl); 335 } 336 } 337 338 static void 339 build_buildid_filename(dwarfstring *target, 340 unsigned buildid_length, 341 unsigned char *buildid) 342 { 343 dwarfstring tmp; 344 unsigned bu = 0; 345 unsigned char *cp = 0; 346 347 dwarfstring_constructor(&tmp); 348 cp = buildid; 349 for (bu = 0; bu < buildid_length; ++bu ,++cp) { 350 dwarfstring_append_printf_u(&tmp, "%02x",*cp); 351 if (bu == 0) { 352 dwarfstring_append(&tmp,"/"); 353 } 354 } 355 dwarfstring_append(&tmp,".debug"); 356 _dwarf_pathjoinl(target,&tmp); 357 dwarfstring_destructor(&tmp); 358 return; 359 } 360 361 #if 0 362 static void 363 dump_bytes(const char *msg,unsigned char * start, unsigned len) 364 { 365 Dwarf_Small *end = start + len; 366 Dwarf_Small *cur = start; 367 printf("%s (0x%lx) ",msg,(unsigned long)start); 368 for (; cur < end; cur++) { 369 printf("%02x", *cur); 370 } 371 printf("\n"); 372 } 373 #endif 374 375 376 /* New September 2019. Access to the GNU section named 377 .gnu_debuglink 378 See 379 https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html 380 381 */ 382 int _dwarf_construct_linkedto_path( 383 char **global_prefixes_in, 384 unsigned length_global_prefixes_in, 385 char *pathname_in, 386 char *link_string_in, /* from debug link */ 387 dwarfstring * link_string_fullpath_out, 388 UNUSEDARG unsigned char *crc_in, /* from debug_link, 4 bytes */ 389 unsigned char *buildid, /* from gnu buildid */ 390 unsigned buildid_length, /* from gnu buildid */ 391 char ***paths_out, 392 unsigned *paths_out_length, 393 int *errcode) 394 { 395 char * depath = pathname_in; 396 int res = 0; 397 struct joins_s joind; 398 size_t dirnamelen = 0; 399 struct dwarfstring_list_s base_dwlist; 400 struct dwarfstring_list_s *last_entry = 0; 401 unsigned global_prefix_number = 0; 402 403 dwarfstring_list_constructor(&base_dwlist); 404 construct_js(&joind); 405 build_buildid_filename(&joind.js_buildid_filename, 406 buildid_length, buildid); 407 dirnamelen = mydirlen(depath); 408 if (dirnamelen) { 409 dwarfstring_append_length(&joind.js_dirname, 410 depath,dirnamelen); 411 } 412 dwarfstring_append(&joind.js_basepath,depath+dirnamelen); 413 dwarfstring_append(&joind.js_basename,link_string_in); 414 if (depath[0] != joinchar) { 415 char buffer[2000]; 416 #ifdef TESTING 417 buffer[0] = 0; 418 /* For testing lets use a fake (consistent) 419 base dir. */ 420 strcpy(buffer,"/fake/dir/path"); 421 #else 422 unsigned buflen= sizeof(buffer); 423 char *wdret = 0; 424 425 buffer[0] = 0; 426 wdret = getcwd(buffer,buflen); 427 if (!wdret) { 428 printf("getcwd() issue. Do nothing. " 429 " line %d %s\n",__LINE__,__FILE__); 430 dwarfstring_list_destructor(&base_dwlist); 431 destruct_js(&joind); 432 *errcode = DW_DLE_ALLOC_FAIL; 433 return DW_DLV_ERROR; 434 } 435 #endif /* TESTING */ 436 dwarfstring_append(&joind.js_cwd,buffer); 437 buffer[0] = 0; 438 } 439 440 { 441 /* Builds the full path to the original 442 executable, but absent executable name. */ 443 dwarfstring_append(&joind.js_originalfullpath, 444 dwarfstring_string(&joind.js_cwd)); 445 _dwarf_pathjoinl(&joind.js_originalfullpath, 446 &joind.js_dirname); 447 _dwarf_pathjoinl(&joind.js_originalfullpath, 448 &joind.js_basepath); 449 #ifdef TESTING 450 printf("originalfullpath : %s\n", 451 dwarfstring_string(&joind.js_originalfullpath)); 452 #endif 453 } 454 { 455 /* There is perhaps a directory prefix in the 456 incoming pathname. 457 So we add that to js_cwd. */ 458 res = _dwarf_pathjoinl(&joind.js_cwd, 459 &joind.js_dirname); 460 /* This is used in a couple search paths. */ 461 } 462 for (global_prefix_number = 0; 463 buildid_length && 464 (global_prefix_number < length_global_prefixes_in); 465 ++global_prefix_number) { 466 char * prefix = 0; 467 468 prefix = global_prefixes_in[global_prefix_number]; 469 dwarfstring_reset(&joind.js_buildid); 470 dwarfstring_append(&joind.js_buildid,prefix); 471 _dwarf_pathjoinl(&joind.js_buildid, 472 &joind.js_buildid_filename); 473 if (!strcmp(dwarfstring_string(&joind.js_originalfullpath), 474 dwarfstring_string(&joind.js_buildid))) { 475 #ifdef TESTING 476 printf("duplicated output string %s\n", 477 dwarfstring_string(&joind.js_buildid)); 478 #endif /* TESTING */ 479 /* duplicated name. spurious match. */ 480 } else { 481 struct dwarfstring_list_s *now_last = 0; 482 res = dwarfstring_list_add_new( 483 &base_dwlist, 484 last_entry,&joind.js_buildid, 485 &now_last,errcode); 486 if(res != DW_DLV_OK) { 487 dwarfstring_list_destructor(&base_dwlist); 488 destruct_js(&joind); 489 return res; 490 } 491 last_entry = now_last; 492 } 493 } 494 if (link_string_in) { 495 /* js_cwd is a leading / directory name. */ 496 { 497 dwarfstring_reset(&joind.js_tmp); 498 dwarfstring_append(&joind.js_tmp, 499 dwarfstring_string(&joind.js_cwd)); 500 /* If we add basename do we find what we look for? */ 501 res = _dwarf_pathjoinl(&joind.js_tmp,&joind.js_basename); 502 /* We return the original link as full path this way. */ 503 dwarfstring_append(link_string_fullpath_out, 504 dwarfstring_string(&joind.js_tmp)); 505 if (!strcmp(dwarfstring_string(&joind.js_originalfullpath), 506 dwarfstring_string(&joind.js_tmp))) { 507 #ifdef TESTING 508 printf("duplicated output string %s\n", 509 dwarfstring_string(&joind.js_tmp)); 510 #endif /* TESTING */ 511 /* duplicated name. spurious match. */ 512 } else if (res == DW_DLV_OK) { 513 struct dwarfstring_list_s *now_last = 0; 514 res = dwarfstring_list_add_new( 515 &base_dwlist, 516 last_entry,&joind.js_tmp, 517 &now_last,errcode); 518 if(res != DW_DLV_OK) { 519 dwarfstring_list_destructor(&base_dwlist); 520 destruct_js(&joind); 521 return res; 522 } 523 last_entry = now_last; 524 } 525 } 526 { 527 dwarfstring_reset(&joind.js_tmp2); 528 dwarfstring_reset(&joind.js_tmpdeb); 529 530 dwarfstring_append(&joind.js_tmp2, 531 dwarfstring_string(&joind.js_cwd)); 532 dwarfstring_append(&joind.js_tmpdeb,".debug"); 533 res = _dwarf_pathjoinl(&joind.js_tmp2,&joind.js_tmpdeb); 534 if (res == DW_DLV_OK) { 535 res = _dwarf_pathjoinl(&joind.js_tmp2, 536 &joind.js_basename); 537 /* this the second search path 538 after global directories 539 search for nn/nnnnn....debug. */ 540 if (!strcmp(dwarfstring_string( 541 &joind.js_originalfullpath), 542 dwarfstring_string(&joind.js_tmp2))) { 543 #ifdef TESTING 544 printf("duplicated output string %s\n", 545 dwarfstring_string(&joind.js_tmp2)); 546 #endif /* TESTING */ 547 /* duplicated name. spurious match. */ 548 } else if(res == DW_DLV_OK) { 549 struct dwarfstring_list_s *now_last = 0; 550 res = dwarfstring_list_add_new( 551 &base_dwlist, 552 last_entry,&joind.js_tmp2, 553 &now_last,errcode); 554 if(res != DW_DLV_OK) { 555 dwarfstring_list_destructor(&base_dwlist); 556 destruct_js(&joind); 557 return res; 558 } 559 last_entry = now_last; 560 } 561 } 562 } 563 /* Not found above, now look in the global locations. */ 564 for (global_prefix_number = 0; 565 global_prefix_number < length_global_prefixes_in; 566 ++global_prefix_number) { 567 char * prefix = global_prefixes_in[global_prefix_number]; 568 569 dwarfstring_reset(&joind.js_tmp3); 570 dwarfstring_append(&joind.js_tmp3, prefix); 571 res = _dwarf_pathjoinl(&joind.js_tmp3, &joind.js_cwd); 572 if (res == DW_DLV_OK) { 573 res = _dwarf_pathjoinl(&joind.js_tmp3, 574 &joind.js_basename); 575 if (!strcmp(dwarfstring_string( 576 &joind.js_originalfullpath), 577 dwarfstring_string(&joind.js_tmp3))) { 578 /* duplicated name. spurious match. */ 579 #ifdef TESTING 580 printf("duplicated output string %s\n", 581 dwarfstring_string(&joind.js_tmp3)); 582 #endif /* TESTING */ 583 } else if (res == DW_DLV_OK) { 584 struct dwarfstring_list_s *now_last = 0; 585 res = dwarfstring_list_add_new( 586 &base_dwlist, 587 last_entry,&joind.js_tmp3, 588 &now_last,errcode); 589 if(res != DW_DLV_OK) { 590 dwarfstring_list_destructor(&base_dwlist); 591 destruct_js(&joind); 592 return res; 593 } 594 last_entry = now_last; 595 } 596 } 597 } 598 } 599 600 { 601 struct dwarfstring_list_s *cur = 0; 602 char **resultfullstring = 0; 603 604 unsigned long count = 0; 605 unsigned long pointerarraysize = 0; 606 unsigned long sumstringlengths = 0; 607 unsigned long totalareasize = 0; 608 unsigned long setptrindex = 0; 609 unsigned long setstrindex = 0; 610 611 cur = &base_dwlist; 612 for ( ; cur ; cur = cur->dl_next) { 613 ++count; 614 pointerarraysize += sizeof(void *); 615 sumstringlengths += 616 dwarfstring_strlen(&cur->dl_string) +1; 617 } 618 /* Make a final null pointer in the pointer array. */ 619 pointerarraysize += sizeof(void *); 620 totalareasize = pointerarraysize + sumstringlengths +8; 621 resultfullstring = (char **)malloc(totalareasize); 622 setstrindex = pointerarraysize; 623 if(!resultfullstring) { 624 #ifdef TESTING 625 printf("Malloc fail making final paths. Length %lu" 626 " bytes.\n",totalareasize); 627 #endif /* TESTING */ 628 dwarfstring_list_destructor(&base_dwlist); 629 destruct_js(&joind); 630 *errcode = DW_DLE_ALLOC_FAIL; 631 return DW_DLV_ERROR; 632 } 633 memset(resultfullstring,0,totalareasize); 634 cur = &base_dwlist; 635 636 for ( ; cur ; cur = cur->dl_next,++setptrindex) { 637 char **iptr = (char **)((char *)resultfullstring + 638 setptrindex*sizeof(void *)); 639 char *sptr = (char*)resultfullstring + setstrindex; 640 641 strcpy(sptr,dwarfstring_string(&cur->dl_string)); 642 setstrindex += dwarfstring_strlen(&cur->dl_string)+1; 643 *iptr = sptr; 644 } 645 *paths_out = resultfullstring; 646 *paths_out_length = count; 647 } 648 dwarfstring_list_destructor(&base_dwlist); 649 destruct_js(&joind); 650 return DW_DLV_OK; 651 } 652 653 static int 654 extract_debuglink(Dwarf_Debug dbg, 655 struct Dwarf_Section_s * pdebuglink, 656 char ** name_returned, /* static storage, do not free */ 657 unsigned char ** crc_returned, /* 32bit crc , do not free */ 658 Dwarf_Error *error) 659 { 660 Dwarf_Small *ptr = 0; 661 Dwarf_Small *endptr = 0; 662 unsigned namelen = 0; 663 unsigned m = 0; 664 unsigned incr = 0; 665 Dwarf_Small *crcptr = 0; 666 int res = DW_DLV_ERROR; 667 Dwarf_Unsigned secsize = 0; 668 669 if (!pdebuglink->dss_data) { 670 res = _dwarf_load_section(dbg, pdebuglink,error); 671 if (res != DW_DLV_OK) { 672 return res; 673 } 674 } 675 secsize = pdebuglink->dss_size; 676 ptr = pdebuglink->dss_data; 677 endptr = ptr + secsize; 678 679 res = _dwarf_check_string_valid(dbg,ptr, 680 ptr, endptr, DW_DLE_FORM_STRING_BAD_STRING, 681 error); 682 if ( res != DW_DLV_OK) { 683 return res; 684 } 685 namelen = (unsigned)strlen((const char*)ptr); 686 m = (namelen+1) %4; 687 if (m) { 688 incr = 4 - m; 689 } 690 crcptr = (unsigned char *)ptr +namelen +1 +incr; 691 if ((crcptr +4) != (unsigned char*)endptr) { 692 _dwarf_error(dbg,error,DW_DLE_CORRUPT_GNU_DEBUGLINK); 693 return DW_DLV_ERROR; 694 } 695 *name_returned = (char *)ptr; 696 *crc_returned = crcptr; 697 return DW_DLV_OK; 698 } 699 700 701 /* The definition of .note.gnu.buildid contents (also 702 used for other GNU .note.gnu. sections too. */ 703 struct buildid_s { 704 char bu_ownernamesize[4]; 705 char bu_buildidsize[4]; 706 char bu_type[4]; 707 char bu_owner[1]; 708 }; 709 710 static int 711 extract_buildid(Dwarf_Debug dbg, 712 struct Dwarf_Section_s * pbuildid, 713 unsigned * type_returned, 714 char **owner_name_returned, 715 unsigned char **build_id_returned, 716 unsigned * build_id_length_returned, 717 Dwarf_Error *error) 718 { 719 Dwarf_Small * ptr = 0; 720 Dwarf_Small * endptr = 0; 721 int res = DW_DLV_ERROR; 722 struct buildid_s *bu = 0; 723 Dwarf_Unsigned namesize = 0; 724 Dwarf_Unsigned descrsize = 0; 725 Dwarf_Unsigned type = 0; 726 Dwarf_Unsigned finalsize; 727 Dwarf_Unsigned secsize = 0; 728 729 if (!pbuildid->dss_data) { 730 res = _dwarf_load_section(dbg, pbuildid,error); 731 if (res != DW_DLV_OK) { 732 return res; 733 } 734 } 735 secsize = pbuildid->dss_size; 736 ptr = pbuildid->dss_data; 737 if (secsize < sizeof(struct buildid_s)) { 738 #ifdef TESTING 739 printf("ERROR section .note.gnu.build-id too small: " 740 " section length: 0x%" DW_PR_DUx 741 " minimum struct size 0x%" DW_PR_DUx "\n", 742 secsize,(Dwarf_Unsigned) sizeof(struct buildid_s)); 743 #endif /* TESTING */ 744 _dwarf_error(dbg,error,DW_DLE_CORRUPT_NOTE_GNU_DEBUGID); 745 return DW_DLV_ERROR; 746 } 747 endptr = ptr + secsize; 748 /* We hold gh_content till all is closed 749 as we return pointers into it 750 if all goes well. */ 751 bu = (struct buildid_s *)ptr; 752 ASNAR(dbg->de_copy_word,namesize, bu->bu_ownernamesize); 753 ASNAR(dbg->de_copy_word,descrsize,bu->bu_buildidsize); 754 ASNAR(dbg->de_copy_word,type, bu->bu_type); 755 if (descrsize != 20) { 756 _dwarf_error(dbg,error,DW_DLE_CORRUPT_NOTE_GNU_DEBUGID); 757 return DW_DLV_ERROR; 758 } 759 res = _dwarf_check_string_valid(dbg, 760 (Dwarf_Small *)&bu->bu_owner[0], 761 (Dwarf_Small *)&bu->bu_owner[0], 762 endptr, 763 DW_DLE_CORRUPT_GNU_DEBUGID_STRING, 764 error); 765 if ( res != DW_DLV_OK) { 766 return res; 767 } 768 if ((strlen(bu->bu_owner) +1) != namesize) { 769 _dwarf_error(dbg,error, DW_DLE_CORRUPT_GNU_DEBUGID_STRING); 770 return res; 771 } 772 773 finalsize = sizeof(struct buildid_s)-1 + namesize + descrsize; 774 if (finalsize > secsize) { 775 _dwarf_error(dbg,error, DW_DLE_CORRUPT_GNU_DEBUGID_SIZE); 776 return DW_DLV_ERROR; 777 } 778 *type_returned = type; 779 *owner_name_returned = &bu->bu_owner[0]; 780 *build_id_length_returned = descrsize; 781 *build_id_returned = (unsigned char *)ptr + 782 sizeof(struct buildid_s)-1 + namesize; 783 return DW_DLV_OK; 784 } 785 786 /* */ 787 int dwarf_gnu_debuglink(Dwarf_Debug dbg, 788 char ** debuglink_path_returned, 789 unsigned char ** crc_returned, 790 char ** debuglink_fullpath_returned, 791 unsigned * debuglink_fullpath_length_returned, 792 793 unsigned * buildid_type_returned , 794 char ** buildid_owner_name_returned, 795 unsigned char ** buildid_returned, 796 unsigned * buildid_length_returned, 797 char *** paths_returned, 798 unsigned * paths_count_returned, 799 Dwarf_Error* error) 800 { 801 dwarfstring debuglink_fullpath; 802 int linkres = DW_DLV_ERROR; 803 int res = DW_DLV_ERROR; 804 char * pathname = 0; 805 int buildidres = 0; 806 int errcode = 0; 807 struct Dwarf_Section_s * pdebuglink = 0; 808 struct Dwarf_Section_s * pbuildid = 0; 809 810 if(!dbg) { 811 _dwarf_error(dbg,error,DW_DLE_DBG_NULL); 812 return DW_DLV_ERROR; 813 } 814 if (dbg->de_gnu_debuglink.dss_size) { 815 pdebuglink = &dbg->de_gnu_debuglink; 816 } 817 if (dbg->de_note_gnu_buildid.dss_size) { 818 pbuildid = &dbg->de_note_gnu_buildid; 819 } 820 if (!pdebuglink && !pbuildid) { 821 return DW_DLV_NO_ENTRY; 822 } 823 if (pdebuglink) { 824 linkres = extract_debuglink(dbg, 825 pdebuglink, 826 debuglink_path_returned, 827 crc_returned, 828 error); 829 if (linkres == DW_DLV_ERROR) { 830 return linkres; 831 } 832 } 833 if (pbuildid) { 834 buildidres = extract_buildid(dbg, 835 pbuildid, 836 buildid_type_returned, 837 buildid_owner_name_returned, 838 buildid_returned, 839 buildid_length_returned, 840 error); 841 if (buildidres == DW_DLV_ERROR) { 842 return buildidres; 843 } 844 } 845 846 dwarfstring_constructor(&debuglink_fullpath); 847 pathname = (char *)dbg->de_path; 848 if (pathname && paths_returned) { 849 res = _dwarf_construct_linkedto_path( 850 (char **)dbg->de_gnu_global_paths, 851 dbg->de_gnu_global_path_count, 852 pathname, 853 *debuglink_path_returned, 854 &debuglink_fullpath, 855 *crc_returned, 856 *buildid_returned, 857 *buildid_length_returned, 858 paths_returned, 859 paths_count_returned, 860 &errcode); 861 if(res != DW_DLV_OK) { 862 dwarfstring_destructor(&debuglink_fullpath); 863 return res; 864 } 865 if (dwarfstring_strlen(&debuglink_fullpath)) { 866 *debuglink_fullpath_returned = 867 strdup(dwarfstring_string(&debuglink_fullpath)); 868 *debuglink_fullpath_length_returned = 869 dwarfstring_strlen(&debuglink_fullpath); 870 } 871 } else if (paths_count_returned) { 872 *paths_count_returned = 0; 873 } 874 dwarfstring_destructor(&debuglink_fullpath); 875 return DW_DLV_OK; 876 } 877 878 /* This should be rarely called and most likely 879 only once (at dbg init time from dwarf_generic_init.c, 880 see set_global_paths_init()). 881 Maybe once or twice later. 882 */ 883 int 884 dwarf_add_debuglink_global_path(Dwarf_Debug dbg, 885 const char *pathname, 886 Dwarf_Error *error) 887 { 888 unsigned glpath_count_in = 0; 889 unsigned glpath_count_out = 0; 890 const char **glpaths = 0; 891 const char * path1 = 0; 892 893 glpath_count_in = dbg->de_gnu_global_path_count; 894 glpath_count_out = glpath_count_in+1; 895 glpaths = (const char **)malloc(sizeof(char *)* 896 glpath_count_out); 897 if (!glpaths) { 898 _dwarf_error(dbg,error,DW_DLE_ALLOC_FAIL); 899 return DW_DLV_ERROR; 900 } 901 if (glpath_count_in) { 902 memcpy(glpaths, dbg->de_gnu_global_paths, 903 sizeof(char *)*glpath_count_in); 904 } 905 path1 = strdup(pathname); 906 if (!path1) { 907 free(glpaths); 908 _dwarf_error(dbg,error,DW_DLE_ALLOC_FAIL); 909 return DW_DLV_ERROR; 910 } 911 free((char *)dbg->de_gnu_global_paths); 912 glpaths[glpath_count_in] = path1; 913 dbg->de_gnu_global_paths = (const char **)glpaths; 914 dbg->de_gnu_global_path_count = glpath_count_out; 915 return DW_DLV_OK; 916 } 917