Austin Schuh | 745610d | 2015-09-06 18:19:50 -0700 | [diff] [blame] | 1 | // -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- |
| 2 | // Copyright (c) 2006, Google Inc. |
| 3 | // All rights reserved. |
Brian Silverman | 20350ac | 2021-11-17 18:19:55 -0800 | [diff] [blame] | 4 | // |
Austin Schuh | 745610d | 2015-09-06 18:19:50 -0700 | [diff] [blame] | 5 | // Redistribution and use in source and binary forms, with or without |
| 6 | // modification, are permitted provided that the following conditions are |
| 7 | // met: |
Brian Silverman | 20350ac | 2021-11-17 18:19:55 -0800 | [diff] [blame] | 8 | // |
Austin Schuh | 745610d | 2015-09-06 18:19:50 -0700 | [diff] [blame] | 9 | // * Redistributions of source code must retain the above copyright |
| 10 | // notice, this list of conditions and the following disclaimer. |
| 11 | // * Redistributions in binary form must reproduce the above |
| 12 | // copyright notice, this list of conditions and the following disclaimer |
| 13 | // in the documentation and/or other materials provided with the |
| 14 | // distribution. |
| 15 | // * Neither the name of Google Inc. nor the names of its |
| 16 | // contributors may be used to endorse or promote products derived from |
| 17 | // this software without specific prior written permission. |
Brian Silverman | 20350ac | 2021-11-17 18:19:55 -0800 | [diff] [blame] | 18 | // |
Austin Schuh | 745610d | 2015-09-06 18:19:50 -0700 | [diff] [blame] | 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 30 | |
| 31 | // All functions here are thread-hostile due to file caching unless |
| 32 | // commented otherwise. |
| 33 | |
| 34 | #ifndef _SYSINFO_H_ |
| 35 | #define _SYSINFO_H_ |
| 36 | |
| 37 | #include <config.h> |
| 38 | |
| 39 | #include <time.h> |
| 40 | #if (defined(_WIN32) || defined(__MINGW32__)) && (!defined(__CYGWIN__) && !defined(__CYGWIN32__)) |
| 41 | #include <windows.h> // for DWORD |
| 42 | #include <tlhelp32.h> // for CreateToolhelp32Snapshot |
| 43 | #endif |
| 44 | #ifdef HAVE_UNISTD_H |
| 45 | #include <unistd.h> // for pid_t |
| 46 | #endif |
| 47 | #include <stddef.h> // for size_t |
| 48 | #include <limits.h> // for PATH_MAX |
| 49 | #include "base/basictypes.h" |
| 50 | #include "base/logging.h" // for RawFD |
| 51 | |
| 52 | // This getenv function is safe to call before the C runtime is initialized. |
| 53 | // On Windows, it utilizes GetEnvironmentVariable() and on unix it uses |
| 54 | // /proc/self/environ instead calling getenv(). It's intended to be used in |
| 55 | // routines that run before main(), when the state required for getenv() may |
| 56 | // not be set up yet. In particular, errno isn't set up until relatively late |
| 57 | // (after the pthreads library has a chance to make it threadsafe), and |
Brian Silverman | 20350ac | 2021-11-17 18:19:55 -0800 | [diff] [blame] | 58 | // getenv() doesn't work until then. |
Austin Schuh | 745610d | 2015-09-06 18:19:50 -0700 | [diff] [blame] | 59 | // On some platforms, this call will utilize the same, static buffer for |
| 60 | // repeated GetenvBeforeMain() calls. Callers should not expect pointers from |
| 61 | // this routine to be long lived. |
| 62 | // Note that on unix, /proc only has the environment at the time the |
| 63 | // application was started, so this routine ignores setenv() calls/etc. Also |
| 64 | // note it only reads the first 16K of the environment. |
| 65 | extern const char* GetenvBeforeMain(const char* name); |
| 66 | |
| 67 | // This takes as an argument an environment-variable name (like |
| 68 | // CPUPROFILE) whose value is supposed to be a file-path, and sets |
| 69 | // path to that path, and returns true. Non-trivial for surprising |
| 70 | // reasons, as documented in sysinfo.cc. path must have space PATH_MAX. |
| 71 | extern bool GetUniquePathFromEnv(const char* env_name, char* path); |
| 72 | |
Brian Silverman | 20350ac | 2021-11-17 18:19:55 -0800 | [diff] [blame] | 73 | extern int GetSystemCPUsCount(); |
Austin Schuh | 745610d | 2015-09-06 18:19:50 -0700 | [diff] [blame] | 74 | |
| 75 | // Return true if we're running POSIX (e.g., NPTL on Linux) threads, |
| 76 | // as opposed to a non-POSIX thread library. The thing that we care |
| 77 | // about is whether a thread's pid is the same as the thread that |
| 78 | // spawned it. If so, this function returns true. |
| 79 | // Thread-safe. |
| 80 | // Note: We consider false negatives to be OK. |
| 81 | bool HasPosixThreads(); |
| 82 | |
| 83 | #ifndef SWIG // SWIG doesn't like struct Buffer and variable arguments. |
| 84 | |
| 85 | // A ProcMapsIterator abstracts access to /proc/maps for a given |
| 86 | // process. Needs to be stack-allocatable and avoid using stdio/malloc |
| 87 | // so it can be used in the google stack dumper, heap-profiler, etc. |
| 88 | // |
| 89 | // On Windows and Mac OS X, this iterator iterates *only* over DLLs |
| 90 | // mapped into this process space. For Linux, FreeBSD, and Solaris, |
| 91 | // it iterates over *all* mapped memory regions, including anonymous |
| 92 | // mmaps. For other O/Ss, it is unlikely to work at all, and Valid() |
| 93 | // will always return false. Also note: this routine only works on |
| 94 | // FreeBSD if procfs is mounted: make sure this is in your /etc/fstab: |
| 95 | // proc /proc procfs rw 0 0 |
| 96 | class ProcMapsIterator { |
| 97 | public: |
| 98 | struct Buffer { |
| 99 | #ifdef __FreeBSD__ |
| 100 | // FreeBSD requires us to read all of the maps file at once, so |
| 101 | // we have to make a buffer that's "always" big enough |
| 102 | static const size_t kBufSize = 102400; |
| 103 | #else // a one-line buffer is good enough |
| 104 | static const size_t kBufSize = PATH_MAX + 1024; |
| 105 | #endif |
| 106 | char buf_[kBufSize]; |
| 107 | }; |
| 108 | |
| 109 | |
| 110 | // Create a new iterator for the specified pid. pid can be 0 for "self". |
| 111 | explicit ProcMapsIterator(pid_t pid); |
| 112 | |
| 113 | // Create an iterator with specified storage (for use in signal |
| 114 | // handler). "buffer" should point to a ProcMapsIterator::Buffer |
| 115 | // buffer can be NULL in which case a bufer will be allocated. |
| 116 | ProcMapsIterator(pid_t pid, Buffer *buffer); |
| 117 | |
| 118 | // Iterate through maps_backing instead of maps if use_maps_backing |
| 119 | // is true. Otherwise the same as above. buffer can be NULL and |
| 120 | // it will allocate a buffer itself. |
| 121 | ProcMapsIterator(pid_t pid, Buffer *buffer, |
| 122 | bool use_maps_backing); |
| 123 | |
| 124 | // Returns true if the iterator successfully initialized; |
| 125 | bool Valid() const; |
| 126 | |
| 127 | // Returns a pointer to the most recently parsed line. Only valid |
| 128 | // after Next() returns true, and until the iterator is destroyed or |
| 129 | // Next() is called again. This may give strange results on non-Linux |
| 130 | // systems. Prefer FormatLine() if that may be a concern. |
| 131 | const char *CurrentLine() const { return stext_; } |
| 132 | |
| 133 | // Writes the "canonical" form of the /proc/xxx/maps info for a single |
| 134 | // line to the passed-in buffer. Returns the number of bytes written, |
| 135 | // or 0 if it was not able to write the complete line. (To guarantee |
| 136 | // success, buffer should have size at least Buffer::kBufSize.) |
| 137 | // Takes as arguments values set via a call to Next(). The |
| 138 | // "canonical" form of the line (taken from linux's /proc/xxx/maps): |
| 139 | // <start_addr(hex)>-<end_addr(hex)> <perms(rwxp)> <offset(hex)> + |
| 140 | // <major_dev(hex)>:<minor_dev(hex)> <inode> <filename> Note: the |
| 141 | // eg |
| 142 | // 08048000-0804c000 r-xp 00000000 03:01 3793678 /bin/cat |
| 143 | // If you don't have the dev_t (dev), feel free to pass in 0. |
| 144 | // (Next() doesn't return a dev_t, though NextExt does.) |
| 145 | // |
| 146 | // Note: if filename and flags were obtained via a call to Next(), |
| 147 | // then the output of this function is only valid if Next() returned |
| 148 | // true, and only until the iterator is destroyed or Next() is |
| 149 | // called again. (Since filename, at least, points into CurrentLine.) |
| 150 | static int FormatLine(char* buffer, int bufsize, |
| 151 | uint64 start, uint64 end, const char *flags, |
| 152 | uint64 offset, int64 inode, const char *filename, |
| 153 | dev_t dev); |
| 154 | |
| 155 | // Find the next entry in /proc/maps; return true if found or false |
| 156 | // if at the end of the file. |
| 157 | // |
| 158 | // Any of the result pointers can be NULL if you're not interested |
| 159 | // in those values. |
| 160 | // |
| 161 | // If "flags" and "filename" are passed, they end up pointing to |
| 162 | // storage within the ProcMapsIterator that is valid only until the |
| 163 | // iterator is destroyed or Next() is called again. The caller may |
| 164 | // modify the contents of these strings (up as far as the first NUL, |
| 165 | // and only until the subsequent call to Next()) if desired. |
| 166 | |
| 167 | // The offsets are all uint64 in order to handle the case of a |
| 168 | // 32-bit process running on a 64-bit kernel |
| 169 | // |
| 170 | // IMPORTANT NOTE: see top-of-class notes for details about what |
| 171 | // mapped regions Next() iterates over, depending on O/S. |
| 172 | // TODO(csilvers): make flags and filename const. |
| 173 | bool Next(uint64 *start, uint64 *end, char **flags, |
| 174 | uint64 *offset, int64 *inode, char **filename); |
| 175 | |
| 176 | bool NextExt(uint64 *start, uint64 *end, char **flags, |
| 177 | uint64 *offset, int64 *inode, char **filename, |
| 178 | uint64 *file_mapping, uint64 *file_pages, |
| 179 | uint64 *anon_mapping, uint64 *anon_pages, |
| 180 | dev_t *dev); |
| 181 | |
| 182 | ~ProcMapsIterator(); |
| 183 | |
| 184 | private: |
| 185 | void Init(pid_t pid, Buffer *buffer, bool use_maps_backing); |
| 186 | |
| 187 | char *ibuf_; // input buffer |
| 188 | char *stext_; // start of text |
| 189 | char *etext_; // end of text |
| 190 | char *nextline_; // start of next line |
| 191 | char *ebuf_; // end of buffer (1 char for a nul) |
| 192 | #if (defined(_WIN32) || defined(__MINGW32__)) && (!defined(__CYGWIN__) && !defined(__CYGWIN32__)) |
| 193 | HANDLE snapshot_; // filehandle on dll info |
| 194 | // In a change from the usual W-A pattern, there is no A variant of |
| 195 | // MODULEENTRY32. Tlhelp32.h #defines the W variant, but not the A. |
| 196 | // We want the original A variants, and this #undef is the only |
| 197 | // way I see to get them. Redefining it when we're done prevents us |
| 198 | // from affecting other .cc files. |
| 199 | # ifdef MODULEENTRY32 // Alias of W |
| 200 | # undef MODULEENTRY32 |
| 201 | MODULEENTRY32 module_; // info about current dll (and dll iterator) |
| 202 | # define MODULEENTRY32 MODULEENTRY32W |
| 203 | # else // It's the ascii, the one we want. |
| 204 | MODULEENTRY32 module_; // info about current dll (and dll iterator) |
| 205 | # endif |
| 206 | #elif defined(__MACH__) |
| 207 | int current_image_; // dll's are called "images" in macos parlance |
| 208 | int current_load_cmd_; // the segment of this dll we're examining |
| 209 | #elif defined(__sun__) // Solaris |
| 210 | int fd_; |
| 211 | char current_filename_[PATH_MAX]; |
| 212 | #else |
| 213 | int fd_; // filehandle on /proc/*/maps |
| 214 | #endif |
| 215 | pid_t pid_; |
| 216 | char flags_[10]; |
| 217 | Buffer* dynamic_buffer_; // dynamically-allocated Buffer |
| 218 | bool using_maps_backing_; // true if we are looking at maps_backing instead of maps. |
| 219 | }; |
| 220 | |
| 221 | #endif /* #ifndef SWIG */ |
| 222 | |
| 223 | // Helper routines |
| 224 | |
| 225 | namespace tcmalloc { |
| 226 | int FillProcSelfMaps(char buf[], int size, bool* wrote_all); |
| 227 | void DumpProcSelfMaps(RawFD fd); |
| 228 | } |
| 229 | |
| 230 | #endif /* #ifndef _SYSINFO_H_ */ |