| OLD | NEW |
| 1 // Copyright (c) 2006, Google Inc. | 1 // Copyright (c) 2006, Google Inc. |
| 2 // All rights reserved. | 2 // All rights reserved. |
| 3 // | 3 // |
| 4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
| 5 // modification, are permitted provided that the following conditions are | 5 // modification, are permitted provided that the following conditions are |
| 6 // met: | 6 // met: |
| 7 // | 7 // |
| 8 // * Redistributions of source code must retain the above copyright | 8 // * Redistributions of source code must retain the above copyright |
| 9 // notice, this list of conditions and the following disclaimer. | 9 // notice, this list of conditions and the following disclaimer. |
| 10 // * Redistributions in binary form must reproduce the above | 10 // * Redistributions in binary form must reproduce the above |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 93 # define saferead(fd, buffer, size) read(fd, buffer, size) | 93 # define saferead(fd, buffer, size) read(fd, buffer, size) |
| 94 # define safeclose(fd) close(fd) | 94 # define safeclose(fd) close(fd) |
| 95 #endif | 95 #endif |
| 96 | 96 |
| 97 // ---------------------------------------------------------------------- | 97 // ---------------------------------------------------------------------- |
| 98 // GetenvBeforeMain() | 98 // GetenvBeforeMain() |
| 99 // GetUniquePathFromEnv() | 99 // GetUniquePathFromEnv() |
| 100 // Some non-trivial getenv-related functions. | 100 // Some non-trivial getenv-related functions. |
| 101 // ---------------------------------------------------------------------- | 101 // ---------------------------------------------------------------------- |
| 102 | 102 |
| 103 // It's not safe to call getenv() in the malloc hooks, because they | |
| 104 // might be called extremely early, before libc is done setting up | |
| 105 // correctly. In particular, the thread library may not be done | |
| 106 // setting up errno. So instead, we use the built-in __environ array | |
| 107 // if it exists, and otherwise read /proc/self/environ directly, using | |
| 108 // system calls to read the file, and thus avoid setting errno. | |
| 109 // /proc/self/environ has a limit of how much data it exports (around | |
| 110 // 8K), so it's not an ideal solution. | |
| 111 const char* GetenvBeforeMain(const char* name) { | 103 const char* GetenvBeforeMain(const char* name) { |
| 112 #if defined(HAVE___ENVIRON) // if we have it, it's declared in unistd.h | |
| 113 const int namelen = strlen(name); | |
| 114 for (char** p = __environ; *p; p++) { | |
| 115 if (!memcmp(*p, name, namelen) && (*p)[namelen] == '=') // it's a match | |
| 116 return *p + namelen+1; // point after = | |
| 117 } | |
| 118 return NULL; | |
| 119 #elif defined(PLATFORM_WINDOWS) | |
| 120 // TODO(mbelshe) - repeated calls to this function will overwrite the | |
| 121 // contents of the static buffer. | |
| 122 static char envbuf[1024]; // enough to hold any envvar we care about | |
| 123 if (!GetEnvironmentVariableA(name, envbuf, sizeof(envbuf)-1)) | |
| 124 return NULL; | |
| 125 return envbuf; | |
| 126 #else | |
| 127 // static is ok because this function should only be called before | 104 // static is ok because this function should only be called before |
| 128 // main(), when we're single-threaded. | 105 // main(), when we're single-threaded. |
| 129 static char envbuf[16<<10]; | 106 static char envbuf[16<<10]; |
| 107 #ifndef PLATFORM_WINDOWS |
| 130 if (*envbuf == '\0') { // haven't read the environ yet | 108 if (*envbuf == '\0') { // haven't read the environ yet |
| 131 int fd = safeopen("/proc/self/environ", O_RDONLY); | 109 int fd = safeopen("/proc/self/environ", O_RDONLY); |
| 132 // The -2 below guarantees the last two bytes of the buffer will be \0\0 | 110 // The -2 below guarantees the last two bytes of the buffer will be \0\0 |
| 133 if (fd == -1 || // unable to open the file, fall back onto libc | 111 if (fd == -1 || // unable to open the file, fall back onto libc |
| 134 saferead(fd, envbuf, sizeof(envbuf) - 2) < 0) { // error reading file | 112 saferead(fd, envbuf, sizeof(envbuf) - 2) < 0) { // error reading file |
| 135 RAW_VLOG(1, "Unable to open /proc/self/environ, falling back " | 113 RAW_VLOG(1, "Unable to open /proc/self/environ, falling back " |
| 136 "on getenv(\"%s\"), which may not work", name); | 114 "on getenv(\"%s\"), which may not work", name); |
| 137 if (fd != -1) safeclose(fd); | 115 if (fd != -1) safeclose(fd); |
| 138 return getenv(name); | 116 return getenv(name); |
| 139 } | 117 } |
| 140 safeclose(fd); | 118 safeclose(fd); |
| 141 } | 119 } |
| 142 const int namelen = strlen(name); | 120 const int namelen = strlen(name); |
| 143 const char* p = envbuf; | 121 const char* p = envbuf; |
| 144 while (*p != '\0') { // will happen at the \0\0 that terminates the buffer | 122 while (*p != '\0') { // will happen at the \0\0 that terminates the buffer |
| 145 // proc file has the format NAME=value\0NAME=value\0NAME=value\0... | 123 // proc file has the format NAME=value\0NAME=value\0NAME=value\0... |
| 146 const char* endp = (char*)memchr(p, '\0', sizeof(envbuf) - (p - envbuf)); | 124 const char* endp = (char*)memchr(p, '\0', sizeof(envbuf) - (p - envbuf)); |
| 147 if (endp == NULL) // this entry isn't NUL terminated | 125 if (endp == NULL) // this entry isn't NUL terminated |
| 148 return NULL; | 126 return NULL; |
| 149 else if (!memcmp(p, name, namelen) && p[namelen] == '=') // it's a match | 127 else if (!memcmp(p, name, namelen) && p[namelen] == '=') // it's a match |
| 150 return p + namelen+1; // point after = | 128 return p + namelen+1; // point after = |
| 151 p = endp + 1; | 129 p = endp + 1; |
| 152 } | 130 } |
| 153 return NULL; // env var never found | 131 return NULL; // env var never found |
| 132 #else |
| 133 // TODO(mbelshe) - repeated calls to this function will overwrite the |
| 134 // contents of the static buffer. |
| 135 if (!GetEnvironmentVariableA(name, envbuf, sizeof(envbuf)-1)) |
| 136 return NULL; |
| 137 return envbuf; |
| 154 #endif | 138 #endif |
| 155 } | 139 } |
| 156 | 140 |
| 157 // This takes as an argument an environment-variable name (like | 141 // This takes as an argument an environment-variable name (like |
| 158 // CPUPROFILE) whose value is supposed to be a file-path, and sets | 142 // CPUPROFILE) whose value is supposed to be a file-path, and sets |
| 159 // path to that path, and returns true. If the env var doesn't exist, | 143 // path to that path, and returns true. If the env var doesn't exist, |
| 160 // or is the empty string, leave path unchanged and returns false. | 144 // or is the empty string, leave path unchanged and returns false. |
| 161 // The reason this is non-trivial is that this function handles munged | 145 // The reason this is non-trivial is that this function handles munged |
| 162 // pathnames. Here's why: | 146 // pathnames. Here's why: |
| 163 // | 147 // |
| (...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 450 | 434 |
| 451 #if defined __linux__ || defined __FreeBSD__ || defined __sun__ || defined __CYG
WIN__ || defined __CYGWIN32__ | 435 #if defined __linux__ || defined __FreeBSD__ || defined __sun__ || defined __CYG
WIN__ || defined __CYGWIN32__ |
| 452 static void ConstructFilename(const char* spec, pid_t pid, | 436 static void ConstructFilename(const char* spec, pid_t pid, |
| 453 char* buf, int buf_size) { | 437 char* buf, int buf_size) { |
| 454 CHECK_LT(snprintf(buf, buf_size, | 438 CHECK_LT(snprintf(buf, buf_size, |
| 455 spec, | 439 spec, |
| 456 pid ? pid : getpid()), buf_size); | 440 pid ? pid : getpid()), buf_size); |
| 457 } | 441 } |
| 458 #endif | 442 #endif |
| 459 | 443 |
| 460 // A templatized helper function instantiated for Mach (OS X) only. | |
| 461 // It can handle finding info for both 32 bits and 64 bits. | |
| 462 // Returns true if it successfully handled the hdr, false else. | |
| 463 #ifdef __MACH__ // Mac OS X, almost certainly | |
| 464 template<uint32_t kMagic, uint32_t kLCSegment, | |
| 465 typename MachHeader, typename SegmentCommand> | |
| 466 static bool NextExtMachHelper(const mach_header* hdr, | |
| 467 int current_image, int current_load_cmd, | |
| 468 uint64 *start, uint64 *end, char **flags, | |
| 469 uint64 *offset, int64 *inode, char **filename, | |
| 470 uint64 *file_mapping, uint64 *file_pages, | |
| 471 uint64 *anon_mapping, uint64 *anon_pages, | |
| 472 dev_t *dev) { | |
| 473 static char kDefaultPerms[5] = "r-xp"; | |
| 474 if (hdr->magic != kMagic) | |
| 475 return false; | |
| 476 const char* lc = (const char *)hdr + sizeof(MachHeader); | |
| 477 // TODO(csilvers): make this not-quadradic (increment and hold state) | |
| 478 for (int j = 0; j < current_load_cmd; j++) // advance to *our* load_cmd | |
| 479 lc += ((const load_command *)lc)->cmdsize; | |
| 480 if (((const load_command *)lc)->cmd == kLCSegment) { | |
| 481 const intptr_t dlloff = _dyld_get_image_vmaddr_slide(current_image); | |
| 482 const SegmentCommand* sc = (const SegmentCommand *)lc; | |
| 483 if (start) *start = sc->vmaddr + dlloff; | |
| 484 if (end) *end = sc->vmaddr + sc->vmsize + dlloff; | |
| 485 if (flags) *flags = kDefaultPerms; // can we do better? | |
| 486 if (offset) *offset = sc->fileoff; | |
| 487 if (inode) *inode = 0; | |
| 488 if (filename) | |
| 489 *filename = const_cast<char*>(_dyld_get_image_name(current_image)); | |
| 490 if (file_mapping) *file_mapping = 0; | |
| 491 if (file_pages) *file_pages = 0; // could we use sc->filesize? | |
| 492 if (anon_mapping) *anon_mapping = 0; | |
| 493 if (anon_pages) *anon_pages = 0; | |
| 494 if (dev) *dev = 0; | |
| 495 return true; | |
| 496 } | |
| 497 | |
| 498 return false; | |
| 499 } | |
| 500 #endif | |
| 501 | |
| 502 ProcMapsIterator::ProcMapsIterator(pid_t pid) { | 444 ProcMapsIterator::ProcMapsIterator(pid_t pid) { |
| 503 Init(pid, NULL, false); | 445 Init(pid, NULL, false); |
| 504 } | 446 } |
| 505 | 447 |
| 506 ProcMapsIterator::ProcMapsIterator(pid_t pid, Buffer *buffer) { | 448 ProcMapsIterator::ProcMapsIterator(pid_t pid, Buffer *buffer) { |
| 507 Init(pid, buffer, false); | 449 Init(pid, buffer, false); |
| 508 } | 450 } |
| 509 | 451 |
| 510 ProcMapsIterator::ProcMapsIterator(pid_t pid, Buffer *buffer, | 452 ProcMapsIterator::ProcMapsIterator(pid_t pid, Buffer *buffer, |
| 511 bool use_maps_backing) { | 453 bool use_maps_backing) { |
| 512 Init(pid, buffer, use_maps_backing); | 454 Init(pid, buffer, use_maps_backing); |
| 513 } | 455 } |
| 514 | 456 |
| 515 void ProcMapsIterator::Init(pid_t pid, Buffer *buffer, | 457 void ProcMapsIterator::Init(pid_t pid, Buffer *buffer, |
| 516 bool use_maps_backing) { | 458 bool use_maps_backing) { |
| 517 pid_ = pid; | |
| 518 using_maps_backing_ = use_maps_backing; | 459 using_maps_backing_ = use_maps_backing; |
| 519 dynamic_buffer_ = NULL; | 460 dynamic_buffer_ = NULL; |
| 520 if (!buffer) { | 461 if (!buffer) { |
| 521 // If the user didn't pass in any buffer storage, allocate it | 462 // If the user didn't pass in any buffer storage, allocate it |
| 522 // now. This is the normal case; the signal handler passes in a | 463 // now. This is the normal case; the signal handler passes in a |
| 523 // static buffer. | 464 // static buffer. |
| 524 buffer = dynamic_buffer_ = new Buffer; | 465 buffer = dynamic_buffer_ = new Buffer; |
| 525 } else { | 466 } else { |
| 526 dynamic_buffer_ = NULL; | 467 dynamic_buffer_ = NULL; |
| 527 } | 468 } |
| (...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 743 | 684 |
| 744 return true; | 685 return true; |
| 745 } while (etext_ > ibuf_); | 686 } while (etext_ > ibuf_); |
| 746 #elif defined(__sun__) | 687 #elif defined(__sun__) |
| 747 // This is based on MA_READ == 4, MA_WRITE == 2, MA_EXEC == 1 | 688 // This is based on MA_READ == 4, MA_WRITE == 2, MA_EXEC == 1 |
| 748 static char kPerms[8][4] = { "---", "--x", "-w-", "-wx", | 689 static char kPerms[8][4] = { "---", "--x", "-w-", "-wx", |
| 749 "r--", "r-x", "rw-", "rwx" }; | 690 "r--", "r-x", "rw-", "rwx" }; |
| 750 COMPILE_ASSERT(MA_READ == 4, solaris_ma_read_must_equal_4); | 691 COMPILE_ASSERT(MA_READ == 4, solaris_ma_read_must_equal_4); |
| 751 COMPILE_ASSERT(MA_WRITE == 2, solaris_ma_write_must_equal_2); | 692 COMPILE_ASSERT(MA_WRITE == 2, solaris_ma_write_must_equal_2); |
| 752 COMPILE_ASSERT(MA_EXEC == 1, solaris_ma_exec_must_equal_1); | 693 COMPILE_ASSERT(MA_EXEC == 1, solaris_ma_exec_must_equal_1); |
| 753 Buffer object_path; | |
| 754 int nread = 0; // fill up buffer with text | 694 int nread = 0; // fill up buffer with text |
| 755 NO_INTR(nread = read(fd_, ibuf_, sizeof(prmap_t))); | 695 NO_INTR(nread = read(fd_, ibuf_, sizeof(prmap_t))); |
| 756 if (nread == sizeof(prmap_t)) { | 696 if (nread == sizeof(prmap_t)) { |
| 757 long inode_from_mapname = 0; | 697 long inode_from_mapname = 0; |
| 758 prmap_t* mapinfo = reinterpret_cast<prmap_t*>(ibuf_); | 698 prmap_t* mapinfo = reinterpret_cast<prmap_t*>(ibuf_); |
| 759 // Best-effort attempt to get the inode from the filename. I think the | 699 // Best-effort attempt to get the inode from the filename. I think the |
| 760 // two middle ints are major and minor device numbers, but I'm not sure. | 700 // two middle ints are major and minor device numbers, but I'm not sure. |
| 761 sscanf(mapinfo->pr_mapname, "ufs.%*d.%*d.%ld", &inode_from_mapname); | 701 sscanf(mapinfo->pr_mapname, "ufs.%*d.%*d.%ld", &inode_from_mapname); |
| 762 | 702 |
| 763 if (pid_ == 0) { | |
| 764 CHECK_LT(snprintf(object_path.buf_, Buffer::kBufSize, | |
| 765 "/proc/self/path/%s", mapinfo->pr_mapname), | |
| 766 Buffer::kBufSize); | |
| 767 } else { | |
| 768 CHECK_LT(snprintf(object_path.buf_, Buffer::kBufSize, | |
| 769 "/proc/%d/path/%s", pid_, mapinfo->pr_mapname), | |
| 770 Buffer::kBufSize); | |
| 771 } | |
| 772 ssize_t len = readlink(object_path.buf_, current_filename_, PATH_MAX); | |
| 773 CHECK_LT(len, PATH_MAX); | |
| 774 if (len < 0) | |
| 775 len = 0; | |
| 776 current_filename_[len] = '\0'; | |
| 777 | |
| 778 if (start) *start = mapinfo->pr_vaddr; | 703 if (start) *start = mapinfo->pr_vaddr; |
| 779 if (end) *end = mapinfo->pr_vaddr + mapinfo->pr_size; | 704 if (end) *end = mapinfo->pr_vaddr + mapinfo->pr_size; |
| 780 if (flags) *flags = kPerms[mapinfo->pr_mflags & 7]; | 705 if (flags) *flags = kPerms[mapinfo->pr_mflags & 7]; |
| 781 if (offset) *offset = mapinfo->pr_offset; | 706 if (offset) *offset = mapinfo->pr_offset; |
| 782 if (inode) *inode = inode_from_mapname; | 707 if (inode) *inode = inode_from_mapname; |
| 783 if (filename) *filename = current_filename_; | 708 // TODO(csilvers): How to map from /proc/map/object to filename? |
| 709 if (filename) *filename = mapinfo->pr_mapname; // format is ufs.?.?.inode |
| 784 if (file_mapping) *file_mapping = 0; | 710 if (file_mapping) *file_mapping = 0; |
| 785 if (file_pages) *file_pages = 0; | 711 if (file_pages) *file_pages = 0; |
| 786 if (anon_mapping) *anon_mapping = 0; | 712 if (anon_mapping) *anon_mapping = 0; |
| 787 if (anon_pages) *anon_pages = 0; | 713 if (anon_pages) *anon_pages = 0; |
| 788 if (dev) *dev = 0; | 714 if (dev) *dev = 0; |
| 789 return true; | 715 return true; |
| 790 } | 716 } |
| 791 #elif defined(__MACH__) | 717 #elif defined(__MACH__) |
| 718 static char kDefaultPerms[5] = "r-xp"; |
| 792 // We return a separate entry for each segment in the DLL. (TODO(csilvers): | 719 // We return a separate entry for each segment in the DLL. (TODO(csilvers): |
| 793 // can we do better?) A DLL ("image") has load-commands, some of which | 720 // can we do better?) A DLL ("image") has load-commands, some of which |
| 794 // talk about segment boundaries. | 721 // talk about segment boundaries. |
| 795 // cf image_for_address from http://svn.digium.com/view/asterisk/team/oej/mini
voicemail/dlfcn.c?revision=53912 | 722 // cf image_for_address from http://svn.digium.com/view/asterisk/team/oej/mini
voicemail/dlfcn.c?revision=53912 |
| 796 for (; current_image_ >= 0; current_image_--) { | 723 for (; current_image_ >= 0; current_image_--) { |
| 797 const mach_header* hdr = _dyld_get_image_header(current_image_); | 724 const mach_header* hdr = _dyld_get_image_header(current_image_); |
| 798 if (!hdr) continue; | 725 if (!hdr) continue; |
| 799 if (current_load_cmd_ < 0) // set up for this image | 726 if (current_load_cmd_ < 0) // set up for this image |
| 800 current_load_cmd_ = hdr->ncmds; // again, go from the top down | 727 current_load_cmd_ = hdr->ncmds; // again, go from the top down |
| 801 | 728 |
| 802 // We start with the next load command (we've already looked at this one). | 729 // We start with the next load command (we've already looked at this one). |
| 803 for (current_load_cmd_--; current_load_cmd_ >= 0; current_load_cmd_--) { | 730 for (current_load_cmd_--; current_load_cmd_ >= 0; current_load_cmd_--) { |
| 804 #ifdef MH_MAGIC_64 | 731 const char* lc = ((const char *)hdr + sizeof(struct mach_header)); |
| 805 if (NextExtMachHelper<MH_MAGIC_64, LC_SEGMENT_64, | 732 // TODO(csilvers): make this not-quadradic (increment and hold state) |
| 806 struct mach_header_64, struct segment_command_64>( | 733 for (int j = 0; j < current_load_cmd_; j++) // advance to *our* load_cmd |
| 807 hdr, current_image_, current_load_cmd_, | 734 lc += ((const load_command *)lc)->cmdsize; |
| 808 start, end, flags, offset, inode, filename, | 735 if (((const load_command *)lc)->cmd == LC_SEGMENT) { |
| 809 file_mapping, file_pages, anon_mapping, | 736 const intptr_t dlloff = _dyld_get_image_vmaddr_slide(current_image_); |
| 810 anon_pages, dev)) { | 737 const segment_command* sc = (const segment_command *)lc; |
| 811 return true; | 738 if (start) *start = sc->vmaddr + dlloff; |
| 812 } | 739 if (end) *end = sc->vmaddr + sc->vmsize + dlloff; |
| 813 #endif | 740 if (flags) *flags = kDefaultPerms; // can we do better? |
| 814 if (NextExtMachHelper<MH_MAGIC, LC_SEGMENT, | 741 if (offset) *offset = sc->fileoff; |
| 815 struct mach_header, struct segment_command>( | 742 if (inode) *inode = 0; |
| 816 hdr, current_image_, current_load_cmd_, | 743 if (filename) |
| 817 start, end, flags, offset, inode, filename, | 744 *filename = const_cast<char*>(_dyld_get_image_name(current_image_)); |
| 818 file_mapping, file_pages, anon_mapping, | 745 if (file_mapping) *file_mapping = 0; |
| 819 anon_pages, dev)) { | 746 if (file_pages) *file_pages = 0; // could we use sc->filesize? |
| 747 if (anon_mapping) *anon_mapping = 0; |
| 748 if (anon_pages) *anon_pages = 0; |
| 749 if (dev) *dev = 0; |
| 820 return true; | 750 return true; |
| 821 } | 751 } |
| 822 } | 752 } |
| 823 // If we get here, no more load_cmd's in this image talk about | 753 // If we get here, no more load_cmd's in this image talk about |
| 824 // segments. Go on to the next image. | 754 // segments. Go on to the next image. |
| 825 } | 755 } |
| 826 #elif defined(PLATFORM_WINDOWS) | 756 #elif defined(PLATFORM_WINDOWS) |
| 827 static char kDefaultPerms[5] = "r-xp"; | 757 static char kDefaultPerms[5] = "r-xp"; |
| 828 BOOL ok; | 758 BOOL ok; |
| 829 if (module_.dwSize == 0) { // only possible before first call | 759 if (module_.dwSize == 0) { // only possible before first call |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 908 ProcMapsIterator::Buffer linebuf; | 838 ProcMapsIterator::Buffer linebuf; |
| 909 while (it.Next(&start, &end, &flags, &offset, &inode, &filename)) { | 839 while (it.Next(&start, &end, &flags, &offset, &inode, &filename)) { |
| 910 int written = it.FormatLine(linebuf.buf_, sizeof(linebuf.buf_), | 840 int written = it.FormatLine(linebuf.buf_, sizeof(linebuf.buf_), |
| 911 start, end, flags, offset, inode, filename, | 841 start, end, flags, offset, inode, filename, |
| 912 0); | 842 0); |
| 913 RawWrite(fd, linebuf.buf_, written); | 843 RawWrite(fd, linebuf.buf_, written); |
| 914 } | 844 } |
| 915 } | 845 } |
| 916 | 846 |
| 917 } // namespace tcmalloc | 847 } // namespace tcmalloc |
| OLD | NEW |