// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- // Copyright (c) 2006, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // All functions here are thread-hostile due to file caching unless // commented otherwise. #ifndef _SYSINFO_H_ #define _SYSINFO_H_ #include #include #if (defined(_WIN32) || defined(__MINGW32__)) && (!defined(__CYGWIN__) && !defined(__CYGWIN32__)) #include // for DWORD #include // for CreateToolhelp32Snapshot #endif #ifdef HAVE_UNISTD_H #include // for pid_t #endif #include // for size_t #include // for PATH_MAX #include "base/basictypes.h" #include "base/logging.h" // for RawFD // This getenv function is safe to call before the C runtime is initialized. // On Windows, it utilizes GetEnvironmentVariable() and on unix it uses // /proc/self/environ instead calling getenv(). It's intended to be used in // routines that run before main(), when the state required for getenv() may // not be set up yet. In particular, errno isn't set up until relatively late // (after the pthreads library has a chance to make it threadsafe), and // getenv() doesn't work until then. // On some platforms, this call will utilize the same, static buffer for // repeated GetenvBeforeMain() calls. Callers should not expect pointers from // this routine to be long lived. // Note that on unix, /proc only has the environment at the time the // application was started, so this routine ignores setenv() calls/etc. Also // note it only reads the first 16K of the environment. extern const char* GetenvBeforeMain(const char* name); // This takes as an argument an environment-variable name (like // CPUPROFILE) whose value is supposed to be a file-path, and sets // path to that path, and returns true. Non-trivial for surprising // reasons, as documented in sysinfo.cc. path must have space PATH_MAX. extern bool GetUniquePathFromEnv(const char* env_name, char* path); extern int GetSystemCPUsCount(); // Return true if we're running POSIX (e.g., NPTL on Linux) threads, // as opposed to a non-POSIX thread library. The thing that we care // about is whether a thread's pid is the same as the thread that // spawned it. If so, this function returns true. // Thread-safe. // Note: We consider false negatives to be OK. bool HasPosixThreads(); #ifndef SWIG // SWIG doesn't like struct Buffer and variable arguments. // A ProcMapsIterator abstracts access to /proc/maps for a given // process. Needs to be stack-allocatable and avoid using stdio/malloc // so it can be used in the google stack dumper, heap-profiler, etc. // // On Windows and Mac OS X, this iterator iterates *only* over DLLs // mapped into this process space. For Linux, FreeBSD, and Solaris, // it iterates over *all* mapped memory regions, including anonymous // mmaps. For other O/Ss, it is unlikely to work at all, and Valid() // will always return false. Also note: this routine only works on // FreeBSD if procfs is mounted: make sure this is in your /etc/fstab: // proc /proc procfs rw 0 0 class ProcMapsIterator { public: struct Buffer { #ifdef __FreeBSD__ // FreeBSD requires us to read all of the maps file at once, so // we have to make a buffer that's "always" big enough static const size_t kBufSize = 102400; #else // a one-line buffer is good enough static const size_t kBufSize = PATH_MAX + 1024; #endif char buf_[kBufSize]; }; // Create a new iterator for the specified pid. pid can be 0 for "self". explicit ProcMapsIterator(pid_t pid); // Create an iterator with specified storage (for use in signal // handler). "buffer" should point to a ProcMapsIterator::Buffer // buffer can be NULL in which case a bufer will be allocated. ProcMapsIterator(pid_t pid, Buffer *buffer); // Iterate through maps_backing instead of maps if use_maps_backing // is true. Otherwise the same as above. buffer can be NULL and // it will allocate a buffer itself. ProcMapsIterator(pid_t pid, Buffer *buffer, bool use_maps_backing); // Returns true if the iterator successfully initialized; bool Valid() const; // Returns a pointer to the most recently parsed line. Only valid // after Next() returns true, and until the iterator is destroyed or // Next() is called again. This may give strange results on non-Linux // systems. Prefer FormatLine() if that may be a concern. const char *CurrentLine() const { return stext_; } // Writes the "canonical" form of the /proc/xxx/maps info for a single // line to the passed-in buffer. Returns the number of bytes written, // or 0 if it was not able to write the complete line. (To guarantee // success, buffer should have size at least Buffer::kBufSize.) // Takes as arguments values set via a call to Next(). The // "canonical" form of the line (taken from linux's /proc/xxx/maps): // - + // : Note: the // eg // 08048000-0804c000 r-xp 00000000 03:01 3793678 /bin/cat // If you don't have the dev_t (dev), feel free to pass in 0. // (Next() doesn't return a dev_t, though NextExt does.) // // Note: if filename and flags were obtained via a call to Next(), // then the output of this function is only valid if Next() returned // true, and only until the iterator is destroyed or Next() is // called again. (Since filename, at least, points into CurrentLine.) static int FormatLine(char* buffer, int bufsize, uint64 start, uint64 end, const char *flags, uint64 offset, int64 inode, const char *filename, dev_t dev); // Find the next entry in /proc/maps; return true if found or false // if at the end of the file. // // Any of the result pointers can be NULL if you're not interested // in those values. // // If "flags" and "filename" are passed, they end up pointing to // storage within the ProcMapsIterator that is valid only until the // iterator is destroyed or Next() is called again. The caller may // modify the contents of these strings (up as far as the first NUL, // and only until the subsequent call to Next()) if desired. // The offsets are all uint64 in order to handle the case of a // 32-bit process running on a 64-bit kernel // // IMPORTANT NOTE: see top-of-class notes for details about what // mapped regions Next() iterates over, depending on O/S. // TODO(csilvers): make flags and filename const. bool Next(uint64 *start, uint64 *end, char **flags, uint64 *offset, int64 *inode, char **filename); bool NextExt(uint64 *start, uint64 *end, char **flags, uint64 *offset, int64 *inode, char **filename, uint64 *file_mapping, uint64 *file_pages, uint64 *anon_mapping, uint64 *anon_pages, dev_t *dev); ~ProcMapsIterator(); private: void Init(pid_t pid, Buffer *buffer, bool use_maps_backing); char *ibuf_; // input buffer char *stext_; // start of text char *etext_; // end of text char *nextline_; // start of next line char *ebuf_; // end of buffer (1 char for a nul) #if (defined(_WIN32) || defined(__MINGW32__)) && (!defined(__CYGWIN__) && !defined(__CYGWIN32__)) HANDLE snapshot_; // filehandle on dll info // In a change from the usual W-A pattern, there is no A variant of // MODULEENTRY32. Tlhelp32.h #defines the W variant, but not the A. // We want the original A variants, and this #undef is the only // way I see to get them. Redefining it when we're done prevents us // from affecting other .cc files. # ifdef MODULEENTRY32 // Alias of W # undef MODULEENTRY32 MODULEENTRY32 module_; // info about current dll (and dll iterator) # define MODULEENTRY32 MODULEENTRY32W # else // It's the ascii, the one we want. MODULEENTRY32 module_; // info about current dll (and dll iterator) # endif #elif defined(__MACH__) int current_image_; // dll's are called "images" in macos parlance int current_load_cmd_; // the segment of this dll we're examining #elif defined(__sun__) // Solaris int fd_; char current_filename_[PATH_MAX]; #else int fd_; // filehandle on /proc/*/maps #endif pid_t pid_; char flags_[10]; Buffer* dynamic_buffer_; // dynamically-allocated Buffer bool using_maps_backing_; // true if we are looking at maps_backing instead of maps. }; #endif /* #ifndef SWIG */ // Helper routines namespace tcmalloc { int FillProcSelfMaps(char buf[], int size, bool* wrote_all); void DumpProcSelfMaps(RawFD fd); } #endif /* #ifndef _SYSINFO_H_ */