chore: apply clang-format
This commit is contained in:
parent
e3f5398aa1
commit
93549f3600
@ -58,7 +58,7 @@ ConstructorInitializerIndentWidth: 4
|
|||||||
ContinuationIndentWidth: 4
|
ContinuationIndentWidth: 4
|
||||||
Cpp11BracedListStyle: true
|
Cpp11BracedListStyle: true
|
||||||
DeriveLineEnding: true
|
DeriveLineEnding: true
|
||||||
DerivePointerAlignment: true
|
DerivePointerAlignment: false
|
||||||
DisableFormat: false
|
DisableFormat: false
|
||||||
ExperimentalAutoDetectBinPacking: false
|
ExperimentalAutoDetectBinPacking: false
|
||||||
FixNamespaceComments: true
|
FixNamespaceComments: true
|
||||||
@ -84,7 +84,7 @@ IncludeIsMainRegex: '([-_](test|unittest))?$'
|
|||||||
IncludeIsMainSourceRegex: ''
|
IncludeIsMainSourceRegex: ''
|
||||||
IndentCaseLabels: true
|
IndentCaseLabels: true
|
||||||
IndentGotoLabels: true
|
IndentGotoLabels: true
|
||||||
IndentPPDirectives: None
|
IndentPPDirectives: AfterHash
|
||||||
IndentWidth: 2
|
IndentWidth: 2
|
||||||
IndentWrappedFunctionNames: false
|
IndentWrappedFunctionNames: false
|
||||||
JavaScriptQuotes: Leave
|
JavaScriptQuotes: Leave
|
||||||
|
|||||||
@ -48,63 +48,64 @@
|
|||||||
#ifndef BASE_COMMANDLINEFLAGS_H__
|
#ifndef BASE_COMMANDLINEFLAGS_H__
|
||||||
#define BASE_COMMANDLINEFLAGS_H__
|
#define BASE_COMMANDLINEFLAGS_H__
|
||||||
|
|
||||||
#include "config.h"
|
#include <cstdlib> // for getenv
|
||||||
#include <cstdlib> // for getenv
|
#include <cstring> // for memchr
|
||||||
#include <cstring> // for memchr
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
#ifdef GLOG_USE_GFLAGS
|
#ifdef GLOG_USE_GFLAGS
|
||||||
|
|
||||||
#include <gflags/gflags.h>
|
# include <gflags/gflags.h>
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#include "glog/logging.h"
|
# include "glog/logging.h"
|
||||||
|
|
||||||
#define DECLARE_VARIABLE(type, shorttype, name, tn) \
|
# define DECLARE_VARIABLE(type, shorttype, name, tn) \
|
||||||
namespace fL##shorttype { \
|
namespace fL##shorttype { \
|
||||||
extern GLOG_EXPORT type FLAGS_##name; \
|
extern GLOG_EXPORT type FLAGS_##name; \
|
||||||
} \
|
} \
|
||||||
using fL##shorttype::FLAGS_##name
|
using fL##shorttype::FLAGS_##name
|
||||||
#define DEFINE_VARIABLE(type, shorttype, name, value, meaning, tn) \
|
# define DEFINE_VARIABLE(type, shorttype, name, value, meaning, tn) \
|
||||||
namespace fL##shorttype { \
|
namespace fL##shorttype { \
|
||||||
GLOG_EXPORT type FLAGS_##name(value); \
|
GLOG_EXPORT type FLAGS_##name(value); \
|
||||||
char FLAGS_no##name; \
|
char FLAGS_no##name; \
|
||||||
} \
|
} \
|
||||||
using fL##shorttype::FLAGS_##name
|
using fL##shorttype::FLAGS_##name
|
||||||
|
|
||||||
// bool specialization
|
// bool specialization
|
||||||
#define DECLARE_bool(name) \
|
# define DECLARE_bool(name) DECLARE_VARIABLE(bool, B, name, bool)
|
||||||
DECLARE_VARIABLE(bool, B, name, bool)
|
# define DEFINE_bool(name, value, meaning) \
|
||||||
#define DEFINE_bool(name, value, meaning) \
|
DEFINE_VARIABLE(bool, B, name, value, meaning, bool)
|
||||||
DEFINE_VARIABLE(bool, B, name, value, meaning, bool)
|
|
||||||
|
|
||||||
// int32 specialization
|
// int32 specialization
|
||||||
#define DECLARE_int32(name) DECLARE_VARIABLE(google::int32, I, name, int32)
|
# define DECLARE_int32(name) DECLARE_VARIABLE(google::int32, I, name, int32)
|
||||||
#define DEFINE_int32(name, value, meaning) \
|
# define DEFINE_int32(name, value, meaning) \
|
||||||
DEFINE_VARIABLE(google::int32, I, name, value, meaning, int32)
|
DEFINE_VARIABLE(google::int32, I, name, value, meaning, int32)
|
||||||
|
|
||||||
// uint32 specialization
|
// uint32 specialization
|
||||||
#ifndef DECLARE_uint32
|
# ifndef DECLARE_uint32
|
||||||
#define DECLARE_uint32(name) DECLARE_VARIABLE(google::uint32, U, name, uint32)
|
# define DECLARE_uint32(name) \
|
||||||
#endif // DECLARE_uint64
|
DECLARE_VARIABLE(google::uint32, U, name, uint32)
|
||||||
#define DEFINE_uint32(name, value, meaning) \
|
# endif // DECLARE_uint64
|
||||||
DEFINE_VARIABLE(google::uint32, U, name, value, meaning, uint32)
|
# define DEFINE_uint32(name, value, meaning) \
|
||||||
|
DEFINE_VARIABLE(google::uint32, U, name, value, meaning, uint32)
|
||||||
|
|
||||||
// Special case for string, because we have to specify the namespace
|
// Special case for string, because we have to specify the namespace
|
||||||
// std::string, which doesn't play nicely with our FLAG__namespace hackery.
|
// std::string, which doesn't play nicely with our FLAG__namespace hackery.
|
||||||
#define DECLARE_string(name) \
|
# define DECLARE_string(name) \
|
||||||
namespace fLS { \
|
namespace fLS { \
|
||||||
extern GLOG_EXPORT std::string& FLAGS_##name; \
|
extern GLOG_EXPORT std::string& FLAGS_##name; \
|
||||||
} \
|
} \
|
||||||
using fLS::FLAGS_##name
|
using fLS::FLAGS_##name
|
||||||
#define DEFINE_string(name, value, meaning) \
|
# define DEFINE_string(name, value, meaning) \
|
||||||
namespace fLS { \
|
namespace fLS { \
|
||||||
std::string FLAGS_##name##_buf(value); \
|
std::string FLAGS_##name##_buf(value); \
|
||||||
GLOG_EXPORT std::string& FLAGS_##name = FLAGS_##name##_buf; \
|
GLOG_EXPORT std::string& FLAGS_##name = FLAGS_##name##_buf; \
|
||||||
char FLAGS_no##name; \
|
char FLAGS_no##name; \
|
||||||
} \
|
} \
|
||||||
using fLS::FLAGS_##name
|
using fLS::FLAGS_##name
|
||||||
|
|
||||||
#endif // GLOG_USE_GFLAGS
|
#endif // GLOG_USE_GFLAGS
|
||||||
|
|
||||||
@ -130,8 +131,7 @@
|
|||||||
// These macros (could be functions, but I don't want to bother with a .cc
|
// These macros (could be functions, but I don't want to bother with a .cc
|
||||||
// file), make it easier to initialize flags from the environment.
|
// file), make it easier to initialize flags from the environment.
|
||||||
|
|
||||||
#define EnvToString(envname, dflt) \
|
#define EnvToString(envname, dflt) (!getenv(envname) ? (dflt) : getenv(envname))
|
||||||
(!getenv(envname) ? (dflt) : getenv(envname))
|
|
||||||
|
|
||||||
#define EnvToBool(envname, dflt) \
|
#define EnvToBool(envname, dflt) \
|
||||||
(!getenv(envname) ? (dflt) \
|
(!getenv(envname) ? (dflt) \
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
// Copyright (c) 2008, Google Inc.
|
// Copyright (c) 2008, Google Inc.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
// modification, are permitted provided that the following conditions are
|
// modification, are permitted provided that the following conditions are
|
||||||
// met:
|
// met:
|
||||||
//
|
//
|
||||||
// * Redistributions of source code must retain the above copyright
|
// * Redistributions of source code must retain the above copyright
|
||||||
// notice, this list of conditions and the following disclaimer.
|
// notice, this list of conditions and the following disclaimer.
|
||||||
// * Redistributions in binary form must reproduce the above
|
// * Redistributions in binary form must reproduce the above
|
||||||
@ -14,7 +14,7 @@
|
|||||||
// * Neither the name of Google Inc. nor the names of its
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
// contributors may be used to endorse or promote products derived from
|
// contributors may be used to endorse or promote products derived from
|
||||||
// this software without specific prior written permission.
|
// this software without specific prior written permission.
|
||||||
//
|
//
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
@ -36,16 +36,14 @@
|
|||||||
class GoogleInitializer {
|
class GoogleInitializer {
|
||||||
public:
|
public:
|
||||||
using void_function = void (*)();
|
using void_function = void (*)();
|
||||||
GoogleInitializer(const char*, void_function f) {
|
GoogleInitializer(const char*, void_function f) { f(); }
|
||||||
f();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define REGISTER_MODULE_INITIALIZER(name, body) \
|
#define REGISTER_MODULE_INITIALIZER(name, body) \
|
||||||
namespace { \
|
namespace { \
|
||||||
static void google_init_module_##name () { body; } \
|
static void google_init_module_##name() { body; } \
|
||||||
GoogleInitializer google_initializer_module_##name(#name, \
|
GoogleInitializer google_initializer_module_##name( \
|
||||||
google_init_module_##name); \
|
#name, google_init_module_##name); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _GOOGLEINIT_H */
|
#endif /* _GOOGLEINIT_H */
|
||||||
|
|||||||
217
src/base/mutex.h
217
src/base/mutex.h
@ -102,55 +102,56 @@
|
|||||||
#ifndef GOOGLE_MUTEX_H_
|
#ifndef GOOGLE_MUTEX_H_
|
||||||
#define GOOGLE_MUTEX_H_
|
#define GOOGLE_MUTEX_H_
|
||||||
|
|
||||||
#include "config.h" // to figure out pthreads support
|
#include "config.h" // to figure out pthreads support
|
||||||
|
|
||||||
#if defined(NO_THREADS)
|
#if defined(NO_THREADS)
|
||||||
typedef int MutexType; // to keep a lock-count
|
typedef int MutexType; // to keep a lock-count
|
||||||
#elif defined(_WIN32) || defined(__CYGWIN__)
|
#elif defined(_WIN32) || defined(__CYGWIN__)
|
||||||
# ifndef WIN32_LEAN_AND_MEAN
|
# ifndef WIN32_LEAN_AND_MEAN
|
||||||
# define WIN32_LEAN_AND_MEAN // We only need minimal includes
|
# define WIN32_LEAN_AND_MEAN // We only need minimal includes
|
||||||
# endif
|
# endif
|
||||||
# ifdef GMUTEX_TRYLOCK
|
# ifdef GMUTEX_TRYLOCK
|
||||||
// We need Windows NT or later for TryEnterCriticalSection(). If you
|
// We need Windows NT or later for TryEnterCriticalSection(). If you
|
||||||
// don't need that functionality, you can remove these _WIN32_WINNT
|
// don't need that functionality, you can remove these _WIN32_WINNT
|
||||||
// lines, and change TryLock() to assert(0) or something.
|
// lines, and change TryLock() to assert(0) or something.
|
||||||
# ifndef _WIN32_WINNT
|
# ifndef _WIN32_WINNT
|
||||||
# define _WIN32_WINNT 0x0400
|
# define _WIN32_WINNT 0x0400
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
// To avoid macro definition of ERROR.
|
// To avoid macro definition of ERROR.
|
||||||
# ifndef NOGDI
|
# ifndef NOGDI
|
||||||
# define NOGDI
|
# define NOGDI
|
||||||
# endif
|
# endif
|
||||||
// To avoid macro definition of min/max.
|
// To avoid macro definition of min/max.
|
||||||
# ifndef NOMINMAX
|
# ifndef NOMINMAX
|
||||||
# define NOMINMAX
|
# define NOMINMAX
|
||||||
# endif
|
# endif
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
typedef CRITICAL_SECTION MutexType;
|
typedef CRITICAL_SECTION MutexType;
|
||||||
#elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
|
#elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
|
||||||
// Needed for pthread_rwlock_*. If it causes problems, you could take it
|
// Needed for pthread_rwlock_*. If it causes problems, you could take it
|
||||||
// out, but then you'd have to unset HAVE_RWLOCK (at least on linux -- it
|
// out, but then you'd have to unset HAVE_RWLOCK (at least on linux -- it
|
||||||
// *does* cause problems for FreeBSD, or MacOSX, but isn't needed
|
// *does* cause problems for FreeBSD, or MacOSX, but isn't needed
|
||||||
// for locking there.)
|
// for locking there.)
|
||||||
# ifdef __linux__
|
# ifdef __linux__
|
||||||
# ifndef _XOPEN_SOURCE // Some other header might have already set it for us.
|
# ifndef _XOPEN_SOURCE // Some other header might have already set it for
|
||||||
# define _XOPEN_SOURCE 500 // may be needed to get the rwlock calls
|
// us.
|
||||||
# endif
|
# define _XOPEN_SOURCE 500 // may be needed to get the rwlock calls
|
||||||
# endif
|
# endif
|
||||||
# include <pthread.h>
|
# endif
|
||||||
|
# include <pthread.h>
|
||||||
using MutexType = pthread_rwlock_t;
|
using MutexType = pthread_rwlock_t;
|
||||||
#elif defined(HAVE_PTHREAD)
|
#elif defined(HAVE_PTHREAD)
|
||||||
# include <pthread.h>
|
# include <pthread.h>
|
||||||
typedef pthread_mutex_t MutexType;
|
typedef pthread_mutex_t MutexType;
|
||||||
#else
|
#else
|
||||||
# error Need to implement mutex.h for your architecture, or #define NO_THREADS
|
# error Need to implement mutex.h for your architecture, or #define NO_THREADS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// We need to include these header files after defining _XOPEN_SOURCE
|
// We need to include these header files after defining _XOPEN_SOURCE
|
||||||
// as they may define the _XOPEN_SOURCE macro.
|
// as they may define the _XOPEN_SOURCE macro.
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstdlib> // for abort()
|
#include <cstdlib> // for abort()
|
||||||
|
|
||||||
#define MUTEX_NAMESPACE glog_internal_namespace_
|
#define MUTEX_NAMESPACE glog_internal_namespace_
|
||||||
|
|
||||||
@ -170,16 +171,16 @@ class Mutex {
|
|||||||
inline void Lock(); // Block if needed until free then acquire exclusively
|
inline void Lock(); // Block if needed until free then acquire exclusively
|
||||||
inline void Unlock(); // Release a lock acquired via Lock()
|
inline void Unlock(); // Release a lock acquired via Lock()
|
||||||
#ifdef GMUTEX_TRYLOCK
|
#ifdef GMUTEX_TRYLOCK
|
||||||
inline bool TryLock(); // If free, Lock() and return true, else return false
|
inline bool TryLock(); // If free, Lock() and return true, else return false
|
||||||
#endif
|
#endif
|
||||||
// Note that on systems that don't support read-write locks, these may
|
// Note that on systems that don't support read-write locks, these may
|
||||||
// be implemented as synonyms to Lock() and Unlock(). So you can use
|
// be implemented as synonyms to Lock() and Unlock(). So you can use
|
||||||
// these for efficiency, but don't use them anyplace where being able
|
// these for efficiency, but don't use them anyplace where being able
|
||||||
// to do shared reads is necessary to avoid deadlock.
|
// to do shared reads is necessary to avoid deadlock.
|
||||||
inline void ReaderLock(); // Block until free or shared then acquire a share
|
inline void ReaderLock(); // Block until free or shared then acquire a share
|
||||||
inline void ReaderUnlock(); // Release a read share of this Mutex
|
inline void ReaderUnlock(); // Release a read share of this Mutex
|
||||||
inline void WriterLock() { Lock(); } // Acquire an exclusive lock
|
inline void WriterLock() { Lock(); } // Acquire an exclusive lock
|
||||||
inline void WriterUnlock() { Unlock(); } // Release a lock from WriterLock()
|
inline void WriterUnlock() { Unlock(); } // Release a lock from WriterLock()
|
||||||
|
|
||||||
// TODO(hamaji): Do nothing, implement correctly.
|
// TODO(hamaji): Do nothing, implement correctly.
|
||||||
inline void AssertHeld() {}
|
inline void AssertHeld() {}
|
||||||
@ -194,10 +195,10 @@ class Mutex {
|
|||||||
inline void SetIsSafe() { is_safe_ = true; }
|
inline void SetIsSafe() { is_safe_ = true; }
|
||||||
|
|
||||||
// Catch the error of writing Mutex when intending MutexLock.
|
// Catch the error of writing Mutex when intending MutexLock.
|
||||||
explicit Mutex(Mutex * /*ignored*/) {}
|
explicit Mutex(Mutex* /*ignored*/) {}
|
||||||
// Disallow "evil" constructors
|
// Disallow "evil" constructors
|
||||||
Mutex(const Mutex &) = delete;
|
Mutex(const Mutex&) = delete;
|
||||||
void operator=(const Mutex &) = delete;
|
void operator=(const Mutex&) = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Now the implementation of Mutex for various systems
|
// Now the implementation of Mutex for various systems
|
||||||
@ -213,71 +214,86 @@ class Mutex {
|
|||||||
// we do nothing, for efficiency. That's why everything is in an
|
// we do nothing, for efficiency. That's why everything is in an
|
||||||
// assert.
|
// assert.
|
||||||
|
|
||||||
Mutex::Mutex() : mutex_(0) { }
|
Mutex::Mutex() : mutex_(0) {}
|
||||||
Mutex::~Mutex() { assert(mutex_ == 0); }
|
Mutex::~Mutex() { assert(mutex_ == 0); }
|
||||||
void Mutex::Lock() { assert(--mutex_ == -1); }
|
void Mutex::Lock() { assert(--mutex_ == -1); }
|
||||||
void Mutex::Unlock() { assert(mutex_++ == -1); }
|
void Mutex::Unlock() { assert(mutex_++ == -1); }
|
||||||
#ifdef GMUTEX_TRYLOCK
|
# ifdef GMUTEX_TRYLOCK
|
||||||
bool Mutex::TryLock() { if (mutex_) return false; Lock(); return true; }
|
bool Mutex::TryLock() {
|
||||||
#endif
|
if (mutex_) return false;
|
||||||
void Mutex::ReaderLock() { assert(++mutex_ > 0); }
|
Lock();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
void Mutex::ReaderLock() { assert(++mutex_ > 0); }
|
||||||
void Mutex::ReaderUnlock() { assert(mutex_-- > 0); }
|
void Mutex::ReaderUnlock() { assert(mutex_-- > 0); }
|
||||||
|
|
||||||
#elif defined(_WIN32) || defined(__CYGWIN__)
|
#elif defined(_WIN32) || defined(__CYGWIN__)
|
||||||
|
|
||||||
Mutex::Mutex() { InitializeCriticalSection(&mutex_); SetIsSafe(); }
|
Mutex::Mutex() {
|
||||||
Mutex::~Mutex() { DeleteCriticalSection(&mutex_); }
|
InitializeCriticalSection(&mutex_);
|
||||||
void Mutex::Lock() { if (is_safe_) EnterCriticalSection(&mutex_); }
|
SetIsSafe();
|
||||||
void Mutex::Unlock() { if (is_safe_) LeaveCriticalSection(&mutex_); }
|
}
|
||||||
#ifdef GMUTEX_TRYLOCK
|
Mutex::~Mutex() { DeleteCriticalSection(&mutex_); }
|
||||||
bool Mutex::TryLock() { return is_safe_ ?
|
void Mutex::Lock() {
|
||||||
TryEnterCriticalSection(&mutex_) != 0 : true; }
|
if (is_safe_) EnterCriticalSection(&mutex_);
|
||||||
#endif
|
}
|
||||||
void Mutex::ReaderLock() { Lock(); } // we don't have read-write locks
|
void Mutex::Unlock() {
|
||||||
|
if (is_safe_) LeaveCriticalSection(&mutex_);
|
||||||
|
}
|
||||||
|
# ifdef GMUTEX_TRYLOCK
|
||||||
|
bool Mutex::TryLock() {
|
||||||
|
return is_safe_ ? TryEnterCriticalSection(&mutex_) != 0 : true;
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
void Mutex::ReaderLock() { Lock(); } // we don't have read-write locks
|
||||||
void Mutex::ReaderUnlock() { Unlock(); }
|
void Mutex::ReaderUnlock() { Unlock(); }
|
||||||
|
|
||||||
#elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
|
#elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
|
||||||
|
|
||||||
#define SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \
|
# define SAFE_PTHREAD(fncall) \
|
||||||
if (is_safe_ && fncall(&mutex_) != 0) abort(); \
|
do { /* run fncall if is_safe_ is true */ \
|
||||||
} while (0)
|
if (is_safe_ && fncall(&mutex_) != 0) abort(); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
Mutex::Mutex() {
|
Mutex::Mutex() {
|
||||||
SetIsSafe();
|
SetIsSafe();
|
||||||
if (is_safe_ && pthread_rwlock_init(&mutex_, nullptr) != 0) abort();
|
if (is_safe_ && pthread_rwlock_init(&mutex_, nullptr) != 0) abort();
|
||||||
}
|
}
|
||||||
Mutex::~Mutex() { SAFE_PTHREAD(pthread_rwlock_destroy); }
|
Mutex::~Mutex() { SAFE_PTHREAD(pthread_rwlock_destroy); }
|
||||||
void Mutex::Lock() { SAFE_PTHREAD(pthread_rwlock_wrlock); }
|
void Mutex::Lock() { SAFE_PTHREAD(pthread_rwlock_wrlock); }
|
||||||
void Mutex::Unlock() { SAFE_PTHREAD(pthread_rwlock_unlock); }
|
void Mutex::Unlock() { SAFE_PTHREAD(pthread_rwlock_unlock); }
|
||||||
#ifdef GMUTEX_TRYLOCK
|
# ifdef GMUTEX_TRYLOCK
|
||||||
bool Mutex::TryLock() { return is_safe_ ?
|
bool Mutex::TryLock() {
|
||||||
pthread_rwlock_trywrlock(&mutex_) == 0 :
|
return is_safe_ ? pthread_rwlock_trywrlock(&mutex_) == 0 : true;
|
||||||
true; }
|
}
|
||||||
#endif
|
# endif
|
||||||
void Mutex::ReaderLock() { SAFE_PTHREAD(pthread_rwlock_rdlock); }
|
void Mutex::ReaderLock() { SAFE_PTHREAD(pthread_rwlock_rdlock); }
|
||||||
void Mutex::ReaderUnlock() { SAFE_PTHREAD(pthread_rwlock_unlock); }
|
void Mutex::ReaderUnlock() { SAFE_PTHREAD(pthread_rwlock_unlock); }
|
||||||
#undef SAFE_PTHREAD
|
# undef SAFE_PTHREAD
|
||||||
|
|
||||||
#elif defined(HAVE_PTHREAD)
|
#elif defined(HAVE_PTHREAD)
|
||||||
|
|
||||||
#define SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \
|
# define SAFE_PTHREAD(fncall) \
|
||||||
if (is_safe_ && fncall(&mutex_) != 0) abort(); \
|
do { /* run fncall if is_safe_ is true */ \
|
||||||
} while (0)
|
if (is_safe_ && fncall(&mutex_) != 0) abort(); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
Mutex::Mutex() {
|
Mutex::Mutex() {
|
||||||
SetIsSafe();
|
SetIsSafe();
|
||||||
if (is_safe_ && pthread_mutex_init(&mutex_, nullptr) != 0) abort();
|
if (is_safe_ && pthread_mutex_init(&mutex_, nullptr) != 0) abort();
|
||||||
}
|
}
|
||||||
Mutex::~Mutex() { SAFE_PTHREAD(pthread_mutex_destroy); }
|
Mutex::~Mutex() { SAFE_PTHREAD(pthread_mutex_destroy); }
|
||||||
void Mutex::Lock() { SAFE_PTHREAD(pthread_mutex_lock); }
|
void Mutex::Lock() { SAFE_PTHREAD(pthread_mutex_lock); }
|
||||||
void Mutex::Unlock() { SAFE_PTHREAD(pthread_mutex_unlock); }
|
void Mutex::Unlock() { SAFE_PTHREAD(pthread_mutex_unlock); }
|
||||||
#ifdef GMUTEX_TRYLOCK
|
# ifdef GMUTEX_TRYLOCK
|
||||||
bool Mutex::TryLock() { return is_safe_ ?
|
bool Mutex::TryLock() {
|
||||||
pthread_mutex_trylock(&mutex_) == 0 : true; }
|
return is_safe_ ? pthread_mutex_trylock(&mutex_) == 0 : true;
|
||||||
#endif
|
}
|
||||||
void Mutex::ReaderLock() { Lock(); }
|
# endif
|
||||||
|
void Mutex::ReaderLock() { Lock(); }
|
||||||
void Mutex::ReaderUnlock() { Unlock(); }
|
void Mutex::ReaderUnlock() { Unlock(); }
|
||||||
#undef SAFE_PTHREAD
|
# undef SAFE_PTHREAD
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -287,36 +303,39 @@ void Mutex::ReaderUnlock() { Unlock(); }
|
|||||||
// MutexLock(mu) acquires mu when constructed and releases it when destroyed.
|
// MutexLock(mu) acquires mu when constructed and releases it when destroyed.
|
||||||
class MutexLock {
|
class MutexLock {
|
||||||
public:
|
public:
|
||||||
explicit MutexLock(Mutex *mu) : mu_(mu) { mu_->Lock(); }
|
explicit MutexLock(Mutex* mu) : mu_(mu) { mu_->Lock(); }
|
||||||
~MutexLock() { mu_->Unlock(); }
|
~MutexLock() { mu_->Unlock(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Mutex * const mu_;
|
Mutex* const mu_;
|
||||||
// Disallow "evil" constructors
|
// Disallow "evil" constructors
|
||||||
MutexLock(const MutexLock &) = delete;
|
MutexLock(const MutexLock&) = delete;
|
||||||
void operator=(const MutexLock &) = delete;
|
void operator=(const MutexLock&) = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ReaderMutexLock and WriterMutexLock do the same, for rwlocks
|
// ReaderMutexLock and WriterMutexLock do the same, for rwlocks
|
||||||
class ReaderMutexLock {
|
class ReaderMutexLock {
|
||||||
public:
|
public:
|
||||||
explicit ReaderMutexLock(Mutex *mu) : mu_(mu) { mu_->ReaderLock(); }
|
explicit ReaderMutexLock(Mutex* mu) : mu_(mu) { mu_->ReaderLock(); }
|
||||||
~ReaderMutexLock() { mu_->ReaderUnlock(); }
|
~ReaderMutexLock() { mu_->ReaderUnlock(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Mutex * const mu_;
|
Mutex* const mu_;
|
||||||
// Disallow "evil" constructors
|
// Disallow "evil" constructors
|
||||||
ReaderMutexLock(const ReaderMutexLock &) = delete;
|
ReaderMutexLock(const ReaderMutexLock&) = delete;
|
||||||
void operator=(const ReaderMutexLock &) = delete;
|
void operator=(const ReaderMutexLock&) = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
class WriterMutexLock {
|
class WriterMutexLock {
|
||||||
public:
|
public:
|
||||||
explicit WriterMutexLock(Mutex *mu) : mu_(mu) { mu_->WriterLock(); }
|
explicit WriterMutexLock(Mutex* mu) : mu_(mu) { mu_->WriterLock(); }
|
||||||
~WriterMutexLock() { mu_->WriterUnlock(); }
|
~WriterMutexLock() { mu_->WriterUnlock(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Mutex * const mu_;
|
Mutex* const mu_;
|
||||||
// Disallow "evil" constructors
|
// Disallow "evil" constructors
|
||||||
WriterMutexLock(const WriterMutexLock &) = delete;
|
WriterMutexLock(const WriterMutexLock&) = delete;
|
||||||
void operator=(const WriterMutexLock &) = delete;
|
void operator=(const WriterMutexLock&) = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Catch bug where variable name is omitted, e.g. MutexLock (&mu);
|
// Catch bug where variable name is omitted, e.g. MutexLock (&mu);
|
||||||
@ -330,4 +349,4 @@ using namespace MUTEX_NAMESPACE;
|
|||||||
|
|
||||||
#undef MUTEX_NAMESPACE
|
#undef MUTEX_NAMESPACE
|
||||||
|
|
||||||
#endif /* #define GOOGLE_MUTEX_H__ */
|
#endif /* #define GOOGLE_MUTEX_H__ */
|
||||||
|
|||||||
@ -33,14 +33,14 @@
|
|||||||
#include "googletest.h"
|
#include "googletest.h"
|
||||||
|
|
||||||
#ifdef GLOG_USE_GFLAGS
|
#ifdef GLOG_USE_GFLAGS
|
||||||
#include <gflags/gflags.h>
|
# include <gflags/gflags.h>
|
||||||
using namespace GFLAGS_NAMESPACE;
|
using namespace GFLAGS_NAMESPACE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_LIB_GMOCK
|
#ifdef HAVE_LIB_GMOCK
|
||||||
#include <gmock/gmock.h>
|
# include <gmock/gmock.h>
|
||||||
|
|
||||||
#include "mock-log.h"
|
# include "mock-log.h"
|
||||||
// Introduce several symbols from gmock.
|
// Introduce several symbols from gmock.
|
||||||
using google::glog_testing::ScopedMockLog;
|
using google::glog_testing::ScopedMockLog;
|
||||||
using testing::_;
|
using testing::_;
|
||||||
@ -65,7 +65,7 @@ TEST(CleanImmediately, logging) {
|
|||||||
google::DisableLogCleaner();
|
google::DisableLogCleaner();
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char** argv) {
|
||||||
FLAGS_colorlogtostderr = false;
|
FLAGS_colorlogtostderr = false;
|
||||||
FLAGS_timestamp_in_logfile_name = true;
|
FLAGS_timestamp_in_logfile_name = true;
|
||||||
#ifdef GLOG_USE_GFLAGS
|
#ifdef GLOG_USE_GFLAGS
|
||||||
|
|||||||
@ -33,14 +33,14 @@
|
|||||||
#include "googletest.h"
|
#include "googletest.h"
|
||||||
|
|
||||||
#ifdef GLOG_USE_GFLAGS
|
#ifdef GLOG_USE_GFLAGS
|
||||||
#include <gflags/gflags.h>
|
# include <gflags/gflags.h>
|
||||||
using namespace GFLAGS_NAMESPACE;
|
using namespace GFLAGS_NAMESPACE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_LIB_GMOCK
|
#ifdef HAVE_LIB_GMOCK
|
||||||
#include <gmock/gmock.h>
|
# include <gmock/gmock.h>
|
||||||
|
|
||||||
#include "mock-log.h"
|
# include "mock-log.h"
|
||||||
// Introduce several symbols from gmock.
|
// Introduce several symbols from gmock.
|
||||||
using google::glog_testing::ScopedMockLog;
|
using google::glog_testing::ScopedMockLog;
|
||||||
using testing::_;
|
using testing::_;
|
||||||
@ -70,7 +70,7 @@ TEST(CleanImmediatelyWithAbsolutePrefix, logging) {
|
|||||||
google::DisableLogCleaner();
|
google::DisableLogCleaner();
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char** argv) {
|
||||||
FLAGS_colorlogtostderr = false;
|
FLAGS_colorlogtostderr = false;
|
||||||
FLAGS_timestamp_in_logfile_name = true;
|
FLAGS_timestamp_in_logfile_name = true;
|
||||||
#ifdef GLOG_USE_GFLAGS
|
#ifdef GLOG_USE_GFLAGS
|
||||||
|
|||||||
@ -33,14 +33,14 @@
|
|||||||
#include "googletest.h"
|
#include "googletest.h"
|
||||||
|
|
||||||
#ifdef GLOG_USE_GFLAGS
|
#ifdef GLOG_USE_GFLAGS
|
||||||
#include <gflags/gflags.h>
|
# include <gflags/gflags.h>
|
||||||
using namespace GFLAGS_NAMESPACE;
|
using namespace GFLAGS_NAMESPACE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_LIB_GMOCK
|
#ifdef HAVE_LIB_GMOCK
|
||||||
#include <gmock/gmock.h>
|
# include <gmock/gmock.h>
|
||||||
|
|
||||||
#include "mock-log.h"
|
# include "mock-log.h"
|
||||||
// Introduce several symbols from gmock.
|
// Introduce several symbols from gmock.
|
||||||
using google::glog_testing::ScopedMockLog;
|
using google::glog_testing::ScopedMockLog;
|
||||||
using testing::_;
|
using testing::_;
|
||||||
@ -66,7 +66,7 @@ TEST(CleanImmediatelyWithRelativePrefix, logging) {
|
|||||||
google::DisableLogCleaner();
|
google::DisableLogCleaner();
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char** argv) {
|
||||||
FLAGS_colorlogtostderr = false;
|
FLAGS_colorlogtostderr = false;
|
||||||
FLAGS_timestamp_in_logfile_name = true;
|
FLAGS_timestamp_in_logfile_name = true;
|
||||||
#ifdef GLOG_USE_GFLAGS
|
#ifdef GLOG_USE_GFLAGS
|
||||||
|
|||||||
387
src/demangle.cc
387
src/demangle.cc
@ -43,15 +43,15 @@
|
|||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
|
||||||
#if defined(GLOG_OS_WINDOWS)
|
#if defined(GLOG_OS_WINDOWS)
|
||||||
#include <dbghelp.h>
|
# include <dbghelp.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace google {
|
namespace google {
|
||||||
|
|
||||||
#if !defined(GLOG_OS_WINDOWS)
|
#if !defined(GLOG_OS_WINDOWS)
|
||||||
struct AbbrevPair {
|
struct AbbrevPair {
|
||||||
const char *abbrev;
|
const char* abbrev;
|
||||||
const char *real_name;
|
const char* real_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
// List of operators from Itanium C++ ABI.
|
// List of operators from Itanium C++ ABI.
|
||||||
@ -102,11 +102,11 @@ static const AbbrevPair kSubstitutionList[] = {
|
|||||||
|
|
||||||
// State needed for demangling.
|
// State needed for demangling.
|
||||||
struct State {
|
struct State {
|
||||||
const char *mangled_cur; // Cursor of mangled name.
|
const char* mangled_cur; // Cursor of mangled name.
|
||||||
char *out_cur; // Cursor of output string.
|
char* out_cur; // Cursor of output string.
|
||||||
const char *out_begin; // Beginning of output string.
|
const char* out_begin; // Beginning of output string.
|
||||||
const char *out_end; // End of output string.
|
const char* out_end; // End of output string.
|
||||||
const char *prev_name; // For constructors/destructors.
|
const char* prev_name; // For constructors/destructors.
|
||||||
ssize_t prev_name_length; // For constructors/destructors.
|
ssize_t prev_name_length; // For constructors/destructors.
|
||||||
short nest_level; // For nested names.
|
short nest_level; // For nested names.
|
||||||
bool append; // Append flag.
|
bool append; // Append flag.
|
||||||
@ -118,7 +118,7 @@ struct State {
|
|||||||
|
|
||||||
// We don't use strlen() in libc since it's not guaranteed to be async
|
// We don't use strlen() in libc since it's not guaranteed to be async
|
||||||
// signal safe.
|
// signal safe.
|
||||||
static size_t StrLen(const char *str) {
|
static size_t StrLen(const char* str) {
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
while (*str != '\0') {
|
while (*str != '\0') {
|
||||||
++str;
|
++str;
|
||||||
@ -128,7 +128,7 @@ static size_t StrLen(const char *str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if "str" has at least "n" characters remaining.
|
// Returns true if "str" has at least "n" characters remaining.
|
||||||
static bool AtLeastNumCharsRemaining(const char *str, ssize_t n) {
|
static bool AtLeastNumCharsRemaining(const char* str, ssize_t n) {
|
||||||
for (ssize_t i = 0; i < n; ++i) {
|
for (ssize_t i = 0; i < n; ++i) {
|
||||||
if (str[i] == '\0') {
|
if (str[i] == '\0') {
|
||||||
return false;
|
return false;
|
||||||
@ -138,17 +138,16 @@ static bool AtLeastNumCharsRemaining(const char *str, ssize_t n) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if "str" has "prefix" as a prefix.
|
// Returns true if "str" has "prefix" as a prefix.
|
||||||
static bool StrPrefix(const char *str, const char *prefix) {
|
static bool StrPrefix(const char* str, const char* prefix) {
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
while (str[i] != '\0' && prefix[i] != '\0' &&
|
while (str[i] != '\0' && prefix[i] != '\0' && str[i] == prefix[i]) {
|
||||||
str[i] == prefix[i]) {
|
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
return prefix[i] == '\0'; // Consumed everything in "prefix".
|
return prefix[i] == '\0'; // Consumed everything in "prefix".
|
||||||
}
|
}
|
||||||
|
|
||||||
static void InitState(State *state, const char *mangled,
|
static void InitState(State* state, const char* mangled, char* out,
|
||||||
char *out, size_t out_size) {
|
size_t out_size) {
|
||||||
state->mangled_cur = mangled;
|
state->mangled_cur = mangled;
|
||||||
state->out_cur = out;
|
state->out_cur = out;
|
||||||
state->out_begin = out;
|
state->out_begin = out;
|
||||||
@ -166,7 +165,7 @@ static void InitState(State *state, const char *mangled,
|
|||||||
// Returns true and advances "mangled_cur" if we find "one_char_token"
|
// Returns true and advances "mangled_cur" if we find "one_char_token"
|
||||||
// at "mangled_cur" position. It is assumed that "one_char_token" does
|
// at "mangled_cur" position. It is assumed that "one_char_token" does
|
||||||
// not contain '\0'.
|
// not contain '\0'.
|
||||||
static bool ParseOneCharToken(State *state, const char one_char_token) {
|
static bool ParseOneCharToken(State* state, const char one_char_token) {
|
||||||
if (state->mangled_cur[0] == one_char_token) {
|
if (state->mangled_cur[0] == one_char_token) {
|
||||||
++state->mangled_cur;
|
++state->mangled_cur;
|
||||||
return true;
|
return true;
|
||||||
@ -177,7 +176,7 @@ static bool ParseOneCharToken(State *state, const char one_char_token) {
|
|||||||
// Returns true and advances "mangled_cur" if we find "two_char_token"
|
// Returns true and advances "mangled_cur" if we find "two_char_token"
|
||||||
// at "mangled_cur" position. It is assumed that "two_char_token" does
|
// at "mangled_cur" position. It is assumed that "two_char_token" does
|
||||||
// not contain '\0'.
|
// not contain '\0'.
|
||||||
static bool ParseTwoCharToken(State *state, const char *two_char_token) {
|
static bool ParseTwoCharToken(State* state, const char* two_char_token) {
|
||||||
if (state->mangled_cur[0] == two_char_token[0] &&
|
if (state->mangled_cur[0] == two_char_token[0] &&
|
||||||
state->mangled_cur[1] == two_char_token[1]) {
|
state->mangled_cur[1] == two_char_token[1]) {
|
||||||
state->mangled_cur += 2;
|
state->mangled_cur += 2;
|
||||||
@ -188,8 +187,8 @@ static bool ParseTwoCharToken(State *state, const char *two_char_token) {
|
|||||||
|
|
||||||
// Returns true and advances "mangled_cur" if we find any character in
|
// Returns true and advances "mangled_cur" if we find any character in
|
||||||
// "char_class" at "mangled_cur" position.
|
// "char_class" at "mangled_cur" position.
|
||||||
static bool ParseCharClass(State *state, const char *char_class) {
|
static bool ParseCharClass(State* state, const char* char_class) {
|
||||||
const char *p = char_class;
|
const char* p = char_class;
|
||||||
for (; *p != '\0'; ++p) {
|
for (; *p != '\0'; ++p) {
|
||||||
if (state->mangled_cur[0] == *p) {
|
if (state->mangled_cur[0] == *p) {
|
||||||
++state->mangled_cur;
|
++state->mangled_cur;
|
||||||
@ -200,13 +199,11 @@ static bool ParseCharClass(State *state, const char *char_class) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This function is used for handling an optional non-terminal.
|
// This function is used for handling an optional non-terminal.
|
||||||
static bool Optional(bool) {
|
static bool Optional(bool) { return true; }
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This function is used for handling <non-terminal>+ syntax.
|
// This function is used for handling <non-terminal>+ syntax.
|
||||||
using ParseFunc = bool (*)(State *);
|
using ParseFunc = bool (*)(State*);
|
||||||
static bool OneOrMore(ParseFunc parse_func, State *state) {
|
static bool OneOrMore(ParseFunc parse_func, State* state) {
|
||||||
if (parse_func(state)) {
|
if (parse_func(state)) {
|
||||||
while (parse_func(state)) {
|
while (parse_func(state)) {
|
||||||
}
|
}
|
||||||
@ -219,7 +216,7 @@ static bool OneOrMore(ParseFunc parse_func, State *state) {
|
|||||||
// always returns true and must be followed by a termination token or a
|
// always returns true and must be followed by a termination token or a
|
||||||
// terminating sequence not handled by parse_func (e.g.
|
// terminating sequence not handled by parse_func (e.g.
|
||||||
// ParseOneCharToken(state, 'E')).
|
// ParseOneCharToken(state, 'E')).
|
||||||
static bool ZeroOrMore(ParseFunc parse_func, State *state) {
|
static bool ZeroOrMore(ParseFunc parse_func, State* state) {
|
||||||
while (parse_func(state)) {
|
while (parse_func(state)) {
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -228,7 +225,7 @@ static bool ZeroOrMore(ParseFunc parse_func, State *state) {
|
|||||||
// Append "str" at "out_cur". If there is an overflow, "overflowed"
|
// Append "str" at "out_cur". If there is an overflow, "overflowed"
|
||||||
// is set to true for later use. The output string is ensured to
|
// is set to true for later use. The output string is ensured to
|
||||||
// always terminate with '\0' as long as there is no overflow.
|
// always terminate with '\0' as long as there is no overflow.
|
||||||
static void Append(State *state, const char * const str, ssize_t length) {
|
static void Append(State* state, const char* const str, ssize_t length) {
|
||||||
if (state->out_cur == nullptr) {
|
if (state->out_cur == nullptr) {
|
||||||
state->overflowed = true;
|
state->overflowed = true;
|
||||||
return;
|
return;
|
||||||
@ -248,23 +245,19 @@ static void Append(State *state, const char * const str, ssize_t length) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We don't use equivalents in libc to avoid locale issues.
|
// We don't use equivalents in libc to avoid locale issues.
|
||||||
static bool IsLower(char c) {
|
static bool IsLower(char c) { return c >= 'a' && c <= 'z'; }
|
||||||
return c >= 'a' && c <= 'z';
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool IsAlpha(char c) {
|
static bool IsAlpha(char c) {
|
||||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool IsDigit(char c) {
|
static bool IsDigit(char c) { return c >= '0' && c <= '9'; }
|
||||||
return c >= '0' && c <= '9';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true if "str" is a function clone suffix. These suffixes are used
|
// Returns true if "str" is a function clone suffix. These suffixes are used
|
||||||
// by GCC 4.5.x and later versions to indicate functions which have been
|
// by GCC 4.5.x and later versions to indicate functions which have been
|
||||||
// cloned during optimization. We treat any sequence (.<alpha>+.<digit>+)+ as
|
// cloned during optimization. We treat any sequence (.<alpha>+.<digit>+)+ as
|
||||||
// a function clone suffix.
|
// a function clone suffix.
|
||||||
static bool IsFunctionCloneSuffix(const char *str) {
|
static bool IsFunctionCloneSuffix(const char* str) {
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
while (str[i] != '\0') {
|
while (str[i] != '\0') {
|
||||||
// Consume a single .<alpha>+.<digit>+ sequence.
|
// Consume a single .<alpha>+.<digit>+ sequence.
|
||||||
@ -288,12 +281,12 @@ static bool IsFunctionCloneSuffix(const char *str) {
|
|||||||
|
|
||||||
// Append "str" with some tweaks, iff "append" state is true.
|
// Append "str" with some tweaks, iff "append" state is true.
|
||||||
// Returns true so that it can be placed in "if" conditions.
|
// Returns true so that it can be placed in "if" conditions.
|
||||||
static void MaybeAppendWithLength(State *state, const char * const str,
|
static void MaybeAppendWithLength(State* state, const char* const str,
|
||||||
ssize_t length) {
|
ssize_t length) {
|
||||||
if (state->append && length > 0) {
|
if (state->append && length > 0) {
|
||||||
// Append a space if the output buffer ends with '<' and "str"
|
// Append a space if the output buffer ends with '<' and "str"
|
||||||
// starts with '<' to avoid <<<.
|
// starts with '<' to avoid <<<.
|
||||||
if (str[0] == '<' && state->out_begin < state->out_cur &&
|
if (str[0] == '<' && state->out_begin < state->out_cur &&
|
||||||
state->out_cur[-1] == '<') {
|
state->out_cur[-1] == '<') {
|
||||||
Append(state, " ", 1);
|
Append(state, " ", 1);
|
||||||
}
|
}
|
||||||
@ -307,7 +300,7 @@ static void MaybeAppendWithLength(State *state, const char * const str,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// A convenient wrapper around MaybeAppendWithLength().
|
// A convenient wrapper around MaybeAppendWithLength().
|
||||||
static bool MaybeAppend(State *state, const char * const str) {
|
static bool MaybeAppend(State* state, const char* const str) {
|
||||||
if (state->append) {
|
if (state->append) {
|
||||||
size_t length = StrLen(str);
|
size_t length = StrLen(str);
|
||||||
MaybeAppendWithLength(state, str, static_cast<ssize_t>(length));
|
MaybeAppendWithLength(state, str, static_cast<ssize_t>(length));
|
||||||
@ -316,45 +309,45 @@ static bool MaybeAppend(State *state, const char * const str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This function is used for handling nested names.
|
// This function is used for handling nested names.
|
||||||
static bool EnterNestedName(State *state) {
|
static bool EnterNestedName(State* state) {
|
||||||
state->nest_level = 0;
|
state->nest_level = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function is used for handling nested names.
|
// This function is used for handling nested names.
|
||||||
static bool LeaveNestedName(State *state, short prev_value) {
|
static bool LeaveNestedName(State* state, short prev_value) {
|
||||||
state->nest_level = prev_value;
|
state->nest_level = prev_value;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable the append mode not to print function parameters, etc.
|
// Disable the append mode not to print function parameters, etc.
|
||||||
static bool DisableAppend(State *state) {
|
static bool DisableAppend(State* state) {
|
||||||
state->append = false;
|
state->append = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore the append mode to the previous state.
|
// Restore the append mode to the previous state.
|
||||||
static bool RestoreAppend(State *state, bool prev_value) {
|
static bool RestoreAppend(State* state, bool prev_value) {
|
||||||
state->append = prev_value;
|
state->append = prev_value;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Increase the nest level for nested names.
|
// Increase the nest level for nested names.
|
||||||
static void MaybeIncreaseNestLevel(State *state) {
|
static void MaybeIncreaseNestLevel(State* state) {
|
||||||
if (state->nest_level > -1) {
|
if (state->nest_level > -1) {
|
||||||
++state->nest_level;
|
++state->nest_level;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Appends :: for nested names if necessary.
|
// Appends :: for nested names if necessary.
|
||||||
static void MaybeAppendSeparator(State *state) {
|
static void MaybeAppendSeparator(State* state) {
|
||||||
if (state->nest_level >= 1) {
|
if (state->nest_level >= 1) {
|
||||||
MaybeAppend(state, "::");
|
MaybeAppend(state, "::");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cancel the last separator if necessary.
|
// Cancel the last separator if necessary.
|
||||||
static void MaybeCancelLastSeparator(State *state) {
|
static void MaybeCancelLastSeparator(State* state) {
|
||||||
if (state->nest_level >= 1 && state->append &&
|
if (state->nest_level >= 1 && state->append &&
|
||||||
state->out_begin <= state->out_cur - 2) {
|
state->out_begin <= state->out_cur - 2) {
|
||||||
state->out_cur -= 2;
|
state->out_cur -= 2;
|
||||||
@ -364,7 +357,7 @@ static void MaybeCancelLastSeparator(State *state) {
|
|||||||
|
|
||||||
// Returns true if the identifier of the given length pointed to by
|
// Returns true if the identifier of the given length pointed to by
|
||||||
// "mangled_cur" is anonymous namespace.
|
// "mangled_cur" is anonymous namespace.
|
||||||
static bool IdentifierIsAnonymousNamespace(State *state, ssize_t length) {
|
static bool IdentifierIsAnonymousNamespace(State* state, ssize_t length) {
|
||||||
static const char anon_prefix[] = "_GLOBAL__N_";
|
static const char anon_prefix[] = "_GLOBAL__N_";
|
||||||
return (length > static_cast<ssize_t>(sizeof(anon_prefix)) -
|
return (length > static_cast<ssize_t>(sizeof(anon_prefix)) -
|
||||||
1 && // Should be longer.
|
1 && // Should be longer.
|
||||||
@ -372,45 +365,45 @@ static bool IdentifierIsAnonymousNamespace(State *state, ssize_t length) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Forward declarations of our parsing functions.
|
// Forward declarations of our parsing functions.
|
||||||
static bool ParseMangledName(State *state);
|
static bool ParseMangledName(State* state);
|
||||||
static bool ParseEncoding(State *state);
|
static bool ParseEncoding(State* state);
|
||||||
static bool ParseName(State *state);
|
static bool ParseName(State* state);
|
||||||
static bool ParseUnscopedName(State *state);
|
static bool ParseUnscopedName(State* state);
|
||||||
static bool ParseUnscopedTemplateName(State *state);
|
static bool ParseUnscopedTemplateName(State* state);
|
||||||
static bool ParseNestedName(State *state);
|
static bool ParseNestedName(State* state);
|
||||||
static bool ParsePrefix(State *state);
|
static bool ParsePrefix(State* state);
|
||||||
static bool ParseUnqualifiedName(State *state);
|
static bool ParseUnqualifiedName(State* state);
|
||||||
static bool ParseSourceName(State *state);
|
static bool ParseSourceName(State* state);
|
||||||
static bool ParseLocalSourceName(State *state);
|
static bool ParseLocalSourceName(State* state);
|
||||||
static bool ParseNumber(State *state, int *number_out);
|
static bool ParseNumber(State* state, int* number_out);
|
||||||
static bool ParseFloatNumber(State *state);
|
static bool ParseFloatNumber(State* state);
|
||||||
static bool ParseSeqId(State *state);
|
static bool ParseSeqId(State* state);
|
||||||
static bool ParseIdentifier(State *state, ssize_t length);
|
static bool ParseIdentifier(State* state, ssize_t length);
|
||||||
static bool ParseAbiTags(State *state);
|
static bool ParseAbiTags(State* state);
|
||||||
static bool ParseAbiTag(State *state);
|
static bool ParseAbiTag(State* state);
|
||||||
static bool ParseOperatorName(State *state);
|
static bool ParseOperatorName(State* state);
|
||||||
static bool ParseSpecialName(State *state);
|
static bool ParseSpecialName(State* state);
|
||||||
static bool ParseCallOffset(State *state);
|
static bool ParseCallOffset(State* state);
|
||||||
static bool ParseNVOffset(State *state);
|
static bool ParseNVOffset(State* state);
|
||||||
static bool ParseVOffset(State *state);
|
static bool ParseVOffset(State* state);
|
||||||
static bool ParseCtorDtorName(State *state);
|
static bool ParseCtorDtorName(State* state);
|
||||||
static bool ParseType(State *state);
|
static bool ParseType(State* state);
|
||||||
static bool ParseCVQualifiers(State *state);
|
static bool ParseCVQualifiers(State* state);
|
||||||
static bool ParseBuiltinType(State *state);
|
static bool ParseBuiltinType(State* state);
|
||||||
static bool ParseFunctionType(State *state);
|
static bool ParseFunctionType(State* state);
|
||||||
static bool ParseBareFunctionType(State *state);
|
static bool ParseBareFunctionType(State* state);
|
||||||
static bool ParseClassEnumType(State *state);
|
static bool ParseClassEnumType(State* state);
|
||||||
static bool ParseArrayType(State *state);
|
static bool ParseArrayType(State* state);
|
||||||
static bool ParsePointerToMemberType(State *state);
|
static bool ParsePointerToMemberType(State* state);
|
||||||
static bool ParseTemplateParam(State *state);
|
static bool ParseTemplateParam(State* state);
|
||||||
static bool ParseTemplateTemplateParam(State *state);
|
static bool ParseTemplateTemplateParam(State* state);
|
||||||
static bool ParseTemplateArgs(State *state);
|
static bool ParseTemplateArgs(State* state);
|
||||||
static bool ParseTemplateArg(State *state);
|
static bool ParseTemplateArg(State* state);
|
||||||
static bool ParseExpression(State *state);
|
static bool ParseExpression(State* state);
|
||||||
static bool ParseExprPrimary(State *state);
|
static bool ParseExprPrimary(State* state);
|
||||||
static bool ParseLocalName(State *state);
|
static bool ParseLocalName(State* state);
|
||||||
static bool ParseDiscriminator(State *state);
|
static bool ParseDiscriminator(State* state);
|
||||||
static bool ParseSubstitution(State *state);
|
static bool ParseSubstitution(State* state);
|
||||||
|
|
||||||
// Implementation note: the following code is a straightforward
|
// Implementation note: the following code is a straightforward
|
||||||
// translation of the Itanium C++ ABI defined in BNF with a couple of
|
// translation of the Itanium C++ ABI defined in BNF with a couple of
|
||||||
@ -443,14 +436,14 @@ static bool ParseSubstitution(State *state);
|
|||||||
// <http://www.codesourcery.com/cxx-abi/abi.html#mangling>
|
// <http://www.codesourcery.com/cxx-abi/abi.html#mangling>
|
||||||
|
|
||||||
// <mangled-name> ::= _Z <encoding>
|
// <mangled-name> ::= _Z <encoding>
|
||||||
static bool ParseMangledName(State *state) {
|
static bool ParseMangledName(State* state) {
|
||||||
return ParseTwoCharToken(state, "_Z") && ParseEncoding(state);
|
return ParseTwoCharToken(state, "_Z") && ParseEncoding(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
// <encoding> ::= <(function) name> <bare-function-type>
|
// <encoding> ::= <(function) name> <bare-function-type>
|
||||||
// ::= <(data) name>
|
// ::= <(data) name>
|
||||||
// ::= <special-name>
|
// ::= <special-name>
|
||||||
static bool ParseEncoding(State *state) {
|
static bool ParseEncoding(State* state) {
|
||||||
State copy = *state;
|
State copy = *state;
|
||||||
if (ParseName(state) && ParseBareFunctionType(state)) {
|
if (ParseName(state) && ParseBareFunctionType(state)) {
|
||||||
return true;
|
return true;
|
||||||
@ -467,14 +460,13 @@ static bool ParseEncoding(State *state) {
|
|||||||
// ::= <unscoped-template-name> <template-args>
|
// ::= <unscoped-template-name> <template-args>
|
||||||
// ::= <unscoped-name>
|
// ::= <unscoped-name>
|
||||||
// ::= <local-name>
|
// ::= <local-name>
|
||||||
static bool ParseName(State *state) {
|
static bool ParseName(State* state) {
|
||||||
if (ParseNestedName(state) || ParseLocalName(state)) {
|
if (ParseNestedName(state) || ParseLocalName(state)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
State copy = *state;
|
State copy = *state;
|
||||||
if (ParseUnscopedTemplateName(state) &&
|
if (ParseUnscopedTemplateName(state) && ParseTemplateArgs(state)) {
|
||||||
ParseTemplateArgs(state)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
*state = copy;
|
*state = copy;
|
||||||
@ -488,14 +480,13 @@ static bool ParseName(State *state) {
|
|||||||
|
|
||||||
// <unscoped-name> ::= <unqualified-name>
|
// <unscoped-name> ::= <unqualified-name>
|
||||||
// ::= St <unqualified-name>
|
// ::= St <unqualified-name>
|
||||||
static bool ParseUnscopedName(State *state) {
|
static bool ParseUnscopedName(State* state) {
|
||||||
if (ParseUnqualifiedName(state)) {
|
if (ParseUnqualifiedName(state)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
State copy = *state;
|
State copy = *state;
|
||||||
if (ParseTwoCharToken(state, "St") &&
|
if (ParseTwoCharToken(state, "St") && MaybeAppend(state, "std::") &&
|
||||||
MaybeAppend(state, "std::") &&
|
|
||||||
ParseUnqualifiedName(state)) {
|
ParseUnqualifiedName(state)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -505,18 +496,16 @@ static bool ParseUnscopedName(State *state) {
|
|||||||
|
|
||||||
// <unscoped-template-name> ::= <unscoped-name>
|
// <unscoped-template-name> ::= <unscoped-name>
|
||||||
// ::= <substitution>
|
// ::= <substitution>
|
||||||
static bool ParseUnscopedTemplateName(State *state) {
|
static bool ParseUnscopedTemplateName(State* state) {
|
||||||
return ParseUnscopedName(state) || ParseSubstitution(state);
|
return ParseUnscopedName(state) || ParseSubstitution(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
// <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E
|
// <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E
|
||||||
// ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
|
// ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
|
||||||
static bool ParseNestedName(State *state) {
|
static bool ParseNestedName(State* state) {
|
||||||
State copy = *state;
|
State copy = *state;
|
||||||
if (ParseOneCharToken(state, 'N') &&
|
if (ParseOneCharToken(state, 'N') && EnterNestedName(state) &&
|
||||||
EnterNestedName(state) &&
|
Optional(ParseCVQualifiers(state)) && ParsePrefix(state) &&
|
||||||
Optional(ParseCVQualifiers(state)) &&
|
|
||||||
ParsePrefix(state) &&
|
|
||||||
LeaveNestedName(state, copy.nest_level) &&
|
LeaveNestedName(state, copy.nest_level) &&
|
||||||
ParseOneCharToken(state, 'E')) {
|
ParseOneCharToken(state, 'E')) {
|
||||||
return true;
|
return true;
|
||||||
@ -536,12 +525,11 @@ static bool ParseNestedName(State *state) {
|
|||||||
// <template-prefix> ::= <prefix> <(template) unqualified-name>
|
// <template-prefix> ::= <prefix> <(template) unqualified-name>
|
||||||
// ::= <template-param>
|
// ::= <template-param>
|
||||||
// ::= <substitution>
|
// ::= <substitution>
|
||||||
static bool ParsePrefix(State *state) {
|
static bool ParsePrefix(State* state) {
|
||||||
bool has_something = false;
|
bool has_something = false;
|
||||||
while (true) {
|
while (true) {
|
||||||
MaybeAppendSeparator(state);
|
MaybeAppendSeparator(state);
|
||||||
if (ParseTemplateParam(state) ||
|
if (ParseTemplateParam(state) || ParseSubstitution(state) ||
|
||||||
ParseSubstitution(state) ||
|
|
||||||
ParseUnscopedName(state)) {
|
ParseUnscopedName(state)) {
|
||||||
has_something = true;
|
has_something = true;
|
||||||
MaybeIncreaseNestLevel(state);
|
MaybeIncreaseNestLevel(state);
|
||||||
@ -561,15 +549,14 @@ static bool ParsePrefix(State *state) {
|
|||||||
// ::= <ctor-dtor-name>
|
// ::= <ctor-dtor-name>
|
||||||
// ::= <source-name> [<abi-tags>]
|
// ::= <source-name> [<abi-tags>]
|
||||||
// ::= <local-source-name> [<abi-tags>]
|
// ::= <local-source-name> [<abi-tags>]
|
||||||
static bool ParseUnqualifiedName(State *state) {
|
static bool ParseUnqualifiedName(State* state) {
|
||||||
return (ParseOperatorName(state) ||
|
return (ParseOperatorName(state) || ParseCtorDtorName(state) ||
|
||||||
ParseCtorDtorName(state) ||
|
|
||||||
(ParseSourceName(state) && Optional(ParseAbiTags(state))) ||
|
(ParseSourceName(state) && Optional(ParseAbiTags(state))) ||
|
||||||
(ParseLocalSourceName(state) && Optional(ParseAbiTags(state))));
|
(ParseLocalSourceName(state) && Optional(ParseAbiTags(state))));
|
||||||
}
|
}
|
||||||
|
|
||||||
// <source-name> ::= <positive length number> <identifier>
|
// <source-name> ::= <positive length number> <identifier>
|
||||||
static bool ParseSourceName(State *state) {
|
static bool ParseSourceName(State* state) {
|
||||||
State copy = *state;
|
State copy = *state;
|
||||||
int length = -1;
|
int length = -1;
|
||||||
if (ParseNumber(state, &length) && ParseIdentifier(state, length)) {
|
if (ParseNumber(state, &length) && ParseIdentifier(state, length)) {
|
||||||
@ -584,7 +571,7 @@ static bool ParseSourceName(State *state) {
|
|||||||
// References:
|
// References:
|
||||||
// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31775
|
// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31775
|
||||||
// http://gcc.gnu.org/viewcvs?view=rev&revision=124467
|
// http://gcc.gnu.org/viewcvs?view=rev&revision=124467
|
||||||
static bool ParseLocalSourceName(State *state) {
|
static bool ParseLocalSourceName(State* state) {
|
||||||
State copy = *state;
|
State copy = *state;
|
||||||
if (ParseOneCharToken(state, 'L') && ParseSourceName(state) &&
|
if (ParseOneCharToken(state, 'L') && ParseSourceName(state) &&
|
||||||
Optional(ParseDiscriminator(state))) {
|
Optional(ParseDiscriminator(state))) {
|
||||||
@ -597,15 +584,15 @@ static bool ParseLocalSourceName(State *state) {
|
|||||||
// <number> ::= [n] <non-negative decimal integer>
|
// <number> ::= [n] <non-negative decimal integer>
|
||||||
// If "number_out" is non-null, then *number_out is set to the value of the
|
// If "number_out" is non-null, then *number_out is set to the value of the
|
||||||
// parsed number on success.
|
// parsed number on success.
|
||||||
static bool ParseNumber(State *state, int *number_out) {
|
static bool ParseNumber(State* state, int* number_out) {
|
||||||
int sign = 1;
|
int sign = 1;
|
||||||
if (ParseOneCharToken(state, 'n')) {
|
if (ParseOneCharToken(state, 'n')) {
|
||||||
sign = -1;
|
sign = -1;
|
||||||
}
|
}
|
||||||
const char *p = state->mangled_cur;
|
const char* p = state->mangled_cur;
|
||||||
int number = 0;
|
int number = 0;
|
||||||
constexpr int int_max_by_10 = std::numeric_limits<int>::max() / 10;
|
constexpr int int_max_by_10 = std::numeric_limits<int>::max() / 10;
|
||||||
for (;*p != '\0'; ++p) {
|
for (; *p != '\0'; ++p) {
|
||||||
if (IsDigit(*p)) {
|
if (IsDigit(*p)) {
|
||||||
// Prevent signed integer overflow when multiplying
|
// Prevent signed integer overflow when multiplying
|
||||||
if (number > int_max_by_10) {
|
if (number > int_max_by_10) {
|
||||||
@ -637,9 +624,9 @@ static bool ParseNumber(State *state, int *number_out) {
|
|||||||
|
|
||||||
// Floating-point literals are encoded using a fixed-length lowercase
|
// Floating-point literals are encoded using a fixed-length lowercase
|
||||||
// hexadecimal string.
|
// hexadecimal string.
|
||||||
static bool ParseFloatNumber(State *state) {
|
static bool ParseFloatNumber(State* state) {
|
||||||
const char *p = state->mangled_cur;
|
const char* p = state->mangled_cur;
|
||||||
for (;*p != '\0'; ++p) {
|
for (; *p != '\0'; ++p) {
|
||||||
if (!IsDigit(*p) && !(*p >= 'a' && *p <= 'f')) {
|
if (!IsDigit(*p) && !(*p >= 'a' && *p <= 'f')) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -653,9 +640,9 @@ static bool ParseFloatNumber(State *state) {
|
|||||||
|
|
||||||
// The <seq-id> is a sequence number in base 36,
|
// The <seq-id> is a sequence number in base 36,
|
||||||
// using digits and upper case letters
|
// using digits and upper case letters
|
||||||
static bool ParseSeqId(State *state) {
|
static bool ParseSeqId(State* state) {
|
||||||
const char *p = state->mangled_cur;
|
const char* p = state->mangled_cur;
|
||||||
for (;*p != '\0'; ++p) {
|
for (; *p != '\0'; ++p) {
|
||||||
if (!IsDigit(*p) && !(*p >= 'A' && *p <= 'Z')) {
|
if (!IsDigit(*p) && !(*p >= 'A' && *p <= 'Z')) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -668,9 +655,8 @@ static bool ParseSeqId(State *state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// <identifier> ::= <unqualified source code identifier> (of given length)
|
// <identifier> ::= <unqualified source code identifier> (of given length)
|
||||||
static bool ParseIdentifier(State *state, ssize_t length) {
|
static bool ParseIdentifier(State* state, ssize_t length) {
|
||||||
if (length == -1 ||
|
if (length == -1 || !AtLeastNumCharsRemaining(state->mangled_cur, length)) {
|
||||||
!AtLeastNumCharsRemaining(state->mangled_cur, length)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (IdentifierIsAnonymousNamespace(state, length)) {
|
if (IdentifierIsAnonymousNamespace(state, length)) {
|
||||||
@ -687,7 +673,7 @@ static bool ParseIdentifier(State *state, ssize_t length) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// <abi-tags> ::= <abi-tag> [<abi-tags>]
|
// <abi-tags> ::= <abi-tag> [<abi-tags>]
|
||||||
static bool ParseAbiTags(State *state) {
|
static bool ParseAbiTags(State* state) {
|
||||||
State copy = *state;
|
State copy = *state;
|
||||||
DisableAppend(state);
|
DisableAppend(state);
|
||||||
if (OneOrMore(ParseAbiTag, state)) {
|
if (OneOrMore(ParseAbiTag, state)) {
|
||||||
@ -699,23 +685,21 @@ static bool ParseAbiTags(State *state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// <abi-tag> ::= B <source-name>
|
// <abi-tag> ::= B <source-name>
|
||||||
static bool ParseAbiTag(State *state) {
|
static bool ParseAbiTag(State* state) {
|
||||||
return ParseOneCharToken(state, 'B') && ParseSourceName(state);
|
return ParseOneCharToken(state, 'B') && ParseSourceName(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
// <operator-name> ::= nw, and other two letters cases
|
// <operator-name> ::= nw, and other two letters cases
|
||||||
// ::= cv <type> # (cast)
|
// ::= cv <type> # (cast)
|
||||||
// ::= v <digit> <source-name> # vendor extended operator
|
// ::= v <digit> <source-name> # vendor extended operator
|
||||||
static bool ParseOperatorName(State *state) {
|
static bool ParseOperatorName(State* state) {
|
||||||
if (!AtLeastNumCharsRemaining(state->mangled_cur, 2)) {
|
if (!AtLeastNumCharsRemaining(state->mangled_cur, 2)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// First check with "cv" (cast) case.
|
// First check with "cv" (cast) case.
|
||||||
State copy = *state;
|
State copy = *state;
|
||||||
if (ParseTwoCharToken(state, "cv") &&
|
if (ParseTwoCharToken(state, "cv") && MaybeAppend(state, "operator ") &&
|
||||||
MaybeAppend(state, "operator ") &&
|
EnterNestedName(state) && ParseType(state) &&
|
||||||
EnterNestedName(state) &&
|
|
||||||
ParseType(state) &&
|
|
||||||
LeaveNestedName(state, copy.nest_level)) {
|
LeaveNestedName(state, copy.nest_level)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -730,12 +714,11 @@ static bool ParseOperatorName(State *state) {
|
|||||||
|
|
||||||
// Other operator names should start with a lower alphabet followed
|
// Other operator names should start with a lower alphabet followed
|
||||||
// by a lower/upper alphabet.
|
// by a lower/upper alphabet.
|
||||||
if (!(IsLower(state->mangled_cur[0]) &&
|
if (!(IsLower(state->mangled_cur[0]) && IsAlpha(state->mangled_cur[1]))) {
|
||||||
IsAlpha(state->mangled_cur[1]))) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// We may want to perform a binary search if we really need speed.
|
// We may want to perform a binary search if we really need speed.
|
||||||
const AbbrevPair *p;
|
const AbbrevPair* p;
|
||||||
for (p = kOperatorList; p->abbrev != nullptr; ++p) {
|
for (p = kOperatorList; p->abbrev != nullptr; ++p) {
|
||||||
if (state->mangled_cur[0] == p->abbrev[0] &&
|
if (state->mangled_cur[0] == p->abbrev[0] &&
|
||||||
state->mangled_cur[1] == p->abbrev[1]) {
|
state->mangled_cur[1] == p->abbrev[1]) {
|
||||||
@ -769,10 +752,9 @@ static bool ParseOperatorName(State *state) {
|
|||||||
//
|
//
|
||||||
// Note: we don't care much about them since they don't appear in
|
// Note: we don't care much about them since they don't appear in
|
||||||
// stack traces. The are special data.
|
// stack traces. The are special data.
|
||||||
static bool ParseSpecialName(State *state) {
|
static bool ParseSpecialName(State* state) {
|
||||||
State copy = *state;
|
State copy = *state;
|
||||||
if (ParseOneCharToken(state, 'T') &&
|
if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "VTIS") &&
|
||||||
ParseCharClass(state, "VTIS") &&
|
|
||||||
ParseType(state)) {
|
ParseType(state)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -784,8 +766,7 @@ static bool ParseSpecialName(State *state) {
|
|||||||
}
|
}
|
||||||
*state = copy;
|
*state = copy;
|
||||||
|
|
||||||
if (ParseTwoCharToken(state, "GV") &&
|
if (ParseTwoCharToken(state, "GV") && ParseName(state)) {
|
||||||
ParseName(state)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
*state = copy;
|
*state = copy;
|
||||||
@ -831,16 +812,16 @@ static bool ParseSpecialName(State *state) {
|
|||||||
|
|
||||||
// <call-offset> ::= h <nv-offset> _
|
// <call-offset> ::= h <nv-offset> _
|
||||||
// ::= v <v-offset> _
|
// ::= v <v-offset> _
|
||||||
static bool ParseCallOffset(State *state) {
|
static bool ParseCallOffset(State* state) {
|
||||||
State copy = *state;
|
State copy = *state;
|
||||||
if (ParseOneCharToken(state, 'h') &&
|
if (ParseOneCharToken(state, 'h') && ParseNVOffset(state) &&
|
||||||
ParseNVOffset(state) && ParseOneCharToken(state, '_')) {
|
ParseOneCharToken(state, '_')) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
*state = copy;
|
*state = copy;
|
||||||
|
|
||||||
if (ParseOneCharToken(state, 'v') &&
|
if (ParseOneCharToken(state, 'v') && ParseVOffset(state) &&
|
||||||
ParseVOffset(state) && ParseOneCharToken(state, '_')) {
|
ParseOneCharToken(state, '_')) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
*state = copy;
|
*state = copy;
|
||||||
@ -849,10 +830,10 @@ static bool ParseCallOffset(State *state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// <nv-offset> ::= <(offset) number>
|
// <nv-offset> ::= <(offset) number>
|
||||||
static bool ParseNVOffset(State *state) { return ParseNumber(state, nullptr); }
|
static bool ParseNVOffset(State* state) { return ParseNumber(state, nullptr); }
|
||||||
|
|
||||||
// <v-offset> ::= <(offset) number> _ <(virtual offset) number>
|
// <v-offset> ::= <(offset) number> _ <(virtual offset) number>
|
||||||
static bool ParseVOffset(State *state) {
|
static bool ParseVOffset(State* state) {
|
||||||
State copy = *state;
|
State copy = *state;
|
||||||
if (ParseNumber(state, nullptr) && ParseOneCharToken(state, '_') &&
|
if (ParseNumber(state, nullptr) && ParseOneCharToken(state, '_') &&
|
||||||
ParseNumber(state, nullptr)) {
|
ParseNumber(state, nullptr)) {
|
||||||
@ -864,20 +845,18 @@ static bool ParseVOffset(State *state) {
|
|||||||
|
|
||||||
// <ctor-dtor-name> ::= C1 | C2 | C3
|
// <ctor-dtor-name> ::= C1 | C2 | C3
|
||||||
// ::= D0 | D1 | D2
|
// ::= D0 | D1 | D2
|
||||||
static bool ParseCtorDtorName(State *state) {
|
static bool ParseCtorDtorName(State* state) {
|
||||||
State copy = *state;
|
State copy = *state;
|
||||||
if (ParseOneCharToken(state, 'C') &&
|
if (ParseOneCharToken(state, 'C') && ParseCharClass(state, "123")) {
|
||||||
ParseCharClass(state, "123")) {
|
const char* const prev_name = state->prev_name;
|
||||||
const char * const prev_name = state->prev_name;
|
|
||||||
const ssize_t prev_name_length = state->prev_name_length;
|
const ssize_t prev_name_length = state->prev_name_length;
|
||||||
MaybeAppendWithLength(state, prev_name, prev_name_length);
|
MaybeAppendWithLength(state, prev_name, prev_name_length);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
*state = copy;
|
*state = copy;
|
||||||
|
|
||||||
if (ParseOneCharToken(state, 'D') &&
|
if (ParseOneCharToken(state, 'D') && ParseCharClass(state, "012")) {
|
||||||
ParseCharClass(state, "012")) {
|
const char* const prev_name = state->prev_name;
|
||||||
const char * const prev_name = state->prev_name;
|
|
||||||
const ssize_t prev_name_length = state->prev_name_length;
|
const ssize_t prev_name_length = state->prev_name_length;
|
||||||
MaybeAppend(state, "~");
|
MaybeAppend(state, "~");
|
||||||
MaybeAppendWithLength(state, prev_name, prev_name_length);
|
MaybeAppendWithLength(state, prev_name, prev_name_length);
|
||||||
@ -907,7 +886,7 @@ static bool ParseCtorDtorName(State *state) {
|
|||||||
// # member access (C++0x)
|
// # member access (C++0x)
|
||||||
// ::= DT <expression> E # decltype of an expression (C++0x)
|
// ::= DT <expression> E # decltype of an expression (C++0x)
|
||||||
//
|
//
|
||||||
static bool ParseType(State *state) {
|
static bool ParseType(State* state) {
|
||||||
// We should check CV-qualifers, and PRGC things first.
|
// We should check CV-qualifers, and PRGC things first.
|
||||||
State copy = *state;
|
State copy = *state;
|
||||||
if (ParseCVQualifiers(state) && ParseType(state)) {
|
if (ParseCVQualifiers(state) && ParseType(state)) {
|
||||||
@ -937,17 +916,13 @@ static bool ParseType(State *state) {
|
|||||||
}
|
}
|
||||||
*state = copy;
|
*state = copy;
|
||||||
|
|
||||||
if (ParseBuiltinType(state) ||
|
if (ParseBuiltinType(state) || ParseFunctionType(state) ||
|
||||||
ParseFunctionType(state) ||
|
ParseClassEnumType(state) || ParseArrayType(state) ||
|
||||||
ParseClassEnumType(state) ||
|
ParsePointerToMemberType(state) || ParseSubstitution(state)) {
|
||||||
ParseArrayType(state) ||
|
|
||||||
ParsePointerToMemberType(state) ||
|
|
||||||
ParseSubstitution(state)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ParseTemplateTemplateParam(state) &&
|
if (ParseTemplateTemplateParam(state) && ParseTemplateArgs(state)) {
|
||||||
ParseTemplateArgs(state)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
*state = copy;
|
*state = copy;
|
||||||
@ -963,7 +938,7 @@ static bool ParseType(State *state) {
|
|||||||
// <CV-qualifiers> ::= [r] [V] [K]
|
// <CV-qualifiers> ::= [r] [V] [K]
|
||||||
// We don't allow empty <CV-qualifiers> to avoid infinite loop in
|
// We don't allow empty <CV-qualifiers> to avoid infinite loop in
|
||||||
// ParseType().
|
// ParseType().
|
||||||
static bool ParseCVQualifiers(State *state) {
|
static bool ParseCVQualifiers(State* state) {
|
||||||
int num_cv_qualifiers = 0;
|
int num_cv_qualifiers = 0;
|
||||||
num_cv_qualifiers += ParseOneCharToken(state, 'r');
|
num_cv_qualifiers += ParseOneCharToken(state, 'r');
|
||||||
num_cv_qualifiers += ParseOneCharToken(state, 'V');
|
num_cv_qualifiers += ParseOneCharToken(state, 'V');
|
||||||
@ -973,8 +948,8 @@ static bool ParseCVQualifiers(State *state) {
|
|||||||
|
|
||||||
// <builtin-type> ::= v, etc.
|
// <builtin-type> ::= v, etc.
|
||||||
// ::= u <source-name>
|
// ::= u <source-name>
|
||||||
static bool ParseBuiltinType(State *state) {
|
static bool ParseBuiltinType(State* state) {
|
||||||
const AbbrevPair *p;
|
const AbbrevPair* p;
|
||||||
for (p = kBuiltinTypeList; p->abbrev != nullptr; ++p) {
|
for (p = kBuiltinTypeList; p->abbrev != nullptr; ++p) {
|
||||||
if (state->mangled_cur[0] == p->abbrev[0]) {
|
if (state->mangled_cur[0] == p->abbrev[0]) {
|
||||||
MaybeAppend(state, p->real_name);
|
MaybeAppend(state, p->real_name);
|
||||||
@ -992,11 +967,11 @@ static bool ParseBuiltinType(State *state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// <function-type> ::= F [Y] <bare-function-type> E
|
// <function-type> ::= F [Y] <bare-function-type> E
|
||||||
static bool ParseFunctionType(State *state) {
|
static bool ParseFunctionType(State* state) {
|
||||||
State copy = *state;
|
State copy = *state;
|
||||||
if (ParseOneCharToken(state, 'F') &&
|
if (ParseOneCharToken(state, 'F') &&
|
||||||
Optional(ParseOneCharToken(state, 'Y')) &&
|
Optional(ParseOneCharToken(state, 'Y')) && ParseBareFunctionType(state) &&
|
||||||
ParseBareFunctionType(state) && ParseOneCharToken(state, 'E')) {
|
ParseOneCharToken(state, 'E')) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
*state = copy;
|
*state = copy;
|
||||||
@ -1004,7 +979,7 @@ static bool ParseFunctionType(State *state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// <bare-function-type> ::= <(signature) type>+
|
// <bare-function-type> ::= <(signature) type>+
|
||||||
static bool ParseBareFunctionType(State *state) {
|
static bool ParseBareFunctionType(State* state) {
|
||||||
State copy = *state;
|
State copy = *state;
|
||||||
DisableAppend(state);
|
DisableAppend(state);
|
||||||
if (OneOrMore(ParseType, state)) {
|
if (OneOrMore(ParseType, state)) {
|
||||||
@ -1017,13 +992,11 @@ static bool ParseBareFunctionType(State *state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// <class-enum-type> ::= <name>
|
// <class-enum-type> ::= <name>
|
||||||
static bool ParseClassEnumType(State *state) {
|
static bool ParseClassEnumType(State* state) { return ParseName(state); }
|
||||||
return ParseName(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
// <array-type> ::= A <(positive dimension) number> _ <(element) type>
|
// <array-type> ::= A <(positive dimension) number> _ <(element) type>
|
||||||
// ::= A [<(dimension) expression>] _ <(element) type>
|
// ::= A [<(dimension) expression>] _ <(element) type>
|
||||||
static bool ParseArrayType(State *state) {
|
static bool ParseArrayType(State* state) {
|
||||||
State copy = *state;
|
State copy = *state;
|
||||||
if (ParseOneCharToken(state, 'A') && ParseNumber(state, nullptr) &&
|
if (ParseOneCharToken(state, 'A') && ParseNumber(state, nullptr) &&
|
||||||
ParseOneCharToken(state, '_') && ParseType(state)) {
|
ParseOneCharToken(state, '_') && ParseType(state)) {
|
||||||
@ -1040,10 +1013,9 @@ static bool ParseArrayType(State *state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// <pointer-to-member-type> ::= M <(class) type> <(member) type>
|
// <pointer-to-member-type> ::= M <(class) type> <(member) type>
|
||||||
static bool ParsePointerToMemberType(State *state) {
|
static bool ParsePointerToMemberType(State* state) {
|
||||||
State copy = *state;
|
State copy = *state;
|
||||||
if (ParseOneCharToken(state, 'M') && ParseType(state) &&
|
if (ParseOneCharToken(state, 'M') && ParseType(state) && ParseType(state)) {
|
||||||
ParseType(state)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
*state = copy;
|
*state = copy;
|
||||||
@ -1052,7 +1024,7 @@ static bool ParsePointerToMemberType(State *state) {
|
|||||||
|
|
||||||
// <template-param> ::= T_
|
// <template-param> ::= T_
|
||||||
// ::= T <parameter-2 non-negative number> _
|
// ::= T <parameter-2 non-negative number> _
|
||||||
static bool ParseTemplateParam(State *state) {
|
static bool ParseTemplateParam(State* state) {
|
||||||
if (ParseTwoCharToken(state, "T_")) {
|
if (ParseTwoCharToken(state, "T_")) {
|
||||||
MaybeAppend(state, "?"); // We don't support template substitutions.
|
MaybeAppend(state, "?"); // We don't support template substitutions.
|
||||||
return true;
|
return true;
|
||||||
@ -1068,20 +1040,17 @@ static bool ParseTemplateParam(State *state) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// <template-template-param> ::= <template-param>
|
// <template-template-param> ::= <template-param>
|
||||||
// ::= <substitution>
|
// ::= <substitution>
|
||||||
static bool ParseTemplateTemplateParam(State *state) {
|
static bool ParseTemplateTemplateParam(State* state) {
|
||||||
return (ParseTemplateParam(state) ||
|
return (ParseTemplateParam(state) || ParseSubstitution(state));
|
||||||
ParseSubstitution(state));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// <template-args> ::= I <template-arg>+ E
|
// <template-args> ::= I <template-arg>+ E
|
||||||
static bool ParseTemplateArgs(State *state) {
|
static bool ParseTemplateArgs(State* state) {
|
||||||
State copy = *state;
|
State copy = *state;
|
||||||
DisableAppend(state);
|
DisableAppend(state);
|
||||||
if (ParseOneCharToken(state, 'I') &&
|
if (ParseOneCharToken(state, 'I') && OneOrMore(ParseTemplateArg, state) &&
|
||||||
OneOrMore(ParseTemplateArg, state) &&
|
|
||||||
ParseOneCharToken(state, 'E')) {
|
ParseOneCharToken(state, 'E')) {
|
||||||
RestoreAppend(state, copy.append);
|
RestoreAppend(state, copy.append);
|
||||||
MaybeAppend(state, "<>");
|
MaybeAppend(state, "<>");
|
||||||
@ -1096,7 +1065,7 @@ static bool ParseTemplateArgs(State *state) {
|
|||||||
// ::= I <template-arg>* E # argument pack
|
// ::= I <template-arg>* E # argument pack
|
||||||
// ::= J <template-arg>* E # argument pack
|
// ::= J <template-arg>* E # argument pack
|
||||||
// ::= X <expression> E
|
// ::= X <expression> E
|
||||||
static bool ParseTemplateArg(State *state) {
|
static bool ParseTemplateArg(State* state) {
|
||||||
// Avoid recursion above max_levels
|
// Avoid recursion above max_levels
|
||||||
constexpr uint32 max_levels = 5;
|
constexpr uint32 max_levels = 5;
|
||||||
|
|
||||||
@ -1107,15 +1076,13 @@ static bool ParseTemplateArg(State *state) {
|
|||||||
|
|
||||||
State copy = *state;
|
State copy = *state;
|
||||||
if ((ParseOneCharToken(state, 'I') || ParseOneCharToken(state, 'J')) &&
|
if ((ParseOneCharToken(state, 'I') || ParseOneCharToken(state, 'J')) &&
|
||||||
ZeroOrMore(ParseTemplateArg, state) &&
|
ZeroOrMore(ParseTemplateArg, state) && ParseOneCharToken(state, 'E')) {
|
||||||
ParseOneCharToken(state, 'E')) {
|
|
||||||
--state->arg_level;
|
--state->arg_level;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
*state = copy;
|
*state = copy;
|
||||||
|
|
||||||
if (ParseType(state) ||
|
if (ParseType(state) || ParseExprPrimary(state)) {
|
||||||
ParseExprPrimary(state)) {
|
|
||||||
--state->arg_level;
|
--state->arg_level;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1139,7 +1106,7 @@ static bool ParseTemplateArg(State *state) {
|
|||||||
// ::= st <type>
|
// ::= st <type>
|
||||||
// ::= sr <type> <unqualified-name> <template-args>
|
// ::= sr <type> <unqualified-name> <template-args>
|
||||||
// ::= sr <type> <unqualified-name>
|
// ::= sr <type> <unqualified-name>
|
||||||
static bool ParseExpression(State *state) {
|
static bool ParseExpression(State* state) {
|
||||||
if (ParseTemplateParam(state) || ParseExprPrimary(state)) {
|
if (ParseTemplateParam(state) || ParseExprPrimary(state)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1153,25 +1120,21 @@ static bool ParseExpression(State *state) {
|
|||||||
++state->expr_level;
|
++state->expr_level;
|
||||||
|
|
||||||
State copy = *state;
|
State copy = *state;
|
||||||
if (ParseOperatorName(state) &&
|
if (ParseOperatorName(state) && ParseExpression(state) &&
|
||||||
ParseExpression(state) &&
|
ParseExpression(state) && ParseExpression(state)) {
|
||||||
ParseExpression(state) &&
|
--state->expr_level;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
*state = copy;
|
||||||
|
|
||||||
|
if (ParseOperatorName(state) && ParseExpression(state) &&
|
||||||
ParseExpression(state)) {
|
ParseExpression(state)) {
|
||||||
--state->expr_level;
|
--state->expr_level;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
*state = copy;
|
*state = copy;
|
||||||
|
|
||||||
if (ParseOperatorName(state) &&
|
if (ParseOperatorName(state) && ParseExpression(state)) {
|
||||||
ParseExpression(state) &&
|
|
||||||
ParseExpression(state)) {
|
|
||||||
--state->expr_level;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
*state = copy;
|
|
||||||
|
|
||||||
if (ParseOperatorName(state) &&
|
|
||||||
ParseExpression(state)) {
|
|
||||||
--state->expr_level;
|
--state->expr_level;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1184,8 +1147,7 @@ static bool ParseExpression(State *state) {
|
|||||||
*state = copy;
|
*state = copy;
|
||||||
|
|
||||||
if (ParseTwoCharToken(state, "sr") && ParseType(state) &&
|
if (ParseTwoCharToken(state, "sr") && ParseType(state) &&
|
||||||
ParseUnqualifiedName(state) &&
|
ParseUnqualifiedName(state) && ParseTemplateArgs(state)) {
|
||||||
ParseTemplateArgs(state)) {
|
|
||||||
--state->expr_level;
|
--state->expr_level;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1205,7 +1167,7 @@ static bool ParseExpression(State *state) {
|
|||||||
// ::= L <mangled-name> E
|
// ::= L <mangled-name> E
|
||||||
// // A bug in g++'s C++ ABI version 2 (-fabi-version=2).
|
// // A bug in g++'s C++ ABI version 2 (-fabi-version=2).
|
||||||
// ::= LZ <encoding> E
|
// ::= LZ <encoding> E
|
||||||
static bool ParseExprPrimary(State *state) {
|
static bool ParseExprPrimary(State* state) {
|
||||||
State copy = *state;
|
State copy = *state;
|
||||||
if (ParseOneCharToken(state, 'L') && ParseType(state) &&
|
if (ParseOneCharToken(state, 'L') && ParseType(state) &&
|
||||||
ParseNumber(state, nullptr) && ParseOneCharToken(state, 'E')) {
|
ParseNumber(state, nullptr) && ParseOneCharToken(state, 'E')) {
|
||||||
@ -1214,8 +1176,7 @@ static bool ParseExprPrimary(State *state) {
|
|||||||
*state = copy;
|
*state = copy;
|
||||||
|
|
||||||
if (ParseOneCharToken(state, 'L') && ParseType(state) &&
|
if (ParseOneCharToken(state, 'L') && ParseType(state) &&
|
||||||
ParseFloatNumber(state) &&
|
ParseFloatNumber(state) && ParseOneCharToken(state, 'E')) {
|
||||||
ParseOneCharToken(state, 'E')) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
*state = copy;
|
*state = copy;
|
||||||
@ -1238,7 +1199,7 @@ static bool ParseExprPrimary(State *state) {
|
|||||||
// <local-name> := Z <(function) encoding> E <(entity) name>
|
// <local-name> := Z <(function) encoding> E <(entity) name>
|
||||||
// [<discriminator>]
|
// [<discriminator>]
|
||||||
// := Z <(function) encoding> E s [<discriminator>]
|
// := Z <(function) encoding> E s [<discriminator>]
|
||||||
static bool ParseLocalName(State *state) {
|
static bool ParseLocalName(State* state) {
|
||||||
// Avoid recursion above max_levels
|
// Avoid recursion above max_levels
|
||||||
constexpr uint32 max_levels = 5;
|
constexpr uint32 max_levels = 5;
|
||||||
if (state->local_level > max_levels) {
|
if (state->local_level > max_levels) {
|
||||||
@ -1265,7 +1226,7 @@ static bool ParseLocalName(State *state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// <discriminator> := _ <(non-negative) number>
|
// <discriminator> := _ <(non-negative) number>
|
||||||
static bool ParseDiscriminator(State *state) {
|
static bool ParseDiscriminator(State* state) {
|
||||||
State copy = *state;
|
State copy = *state;
|
||||||
if (ParseOneCharToken(state, '_') && ParseNumber(state, nullptr)) {
|
if (ParseOneCharToken(state, '_') && ParseNumber(state, nullptr)) {
|
||||||
return true;
|
return true;
|
||||||
@ -1277,7 +1238,7 @@ static bool ParseDiscriminator(State *state) {
|
|||||||
// <substitution> ::= S_
|
// <substitution> ::= S_
|
||||||
// ::= S <seq-id> _
|
// ::= S <seq-id> _
|
||||||
// ::= St, etc.
|
// ::= St, etc.
|
||||||
static bool ParseSubstitution(State *state) {
|
static bool ParseSubstitution(State* state) {
|
||||||
if (ParseTwoCharToken(state, "S_")) {
|
if (ParseTwoCharToken(state, "S_")) {
|
||||||
MaybeAppend(state, "?"); // We don't support substitutions.
|
MaybeAppend(state, "?"); // We don't support substitutions.
|
||||||
return true;
|
return true;
|
||||||
@ -1293,7 +1254,7 @@ static bool ParseSubstitution(State *state) {
|
|||||||
|
|
||||||
// Expand abbreviations like "St" => "std".
|
// Expand abbreviations like "St" => "std".
|
||||||
if (ParseOneCharToken(state, 'S')) {
|
if (ParseOneCharToken(state, 'S')) {
|
||||||
const AbbrevPair *p;
|
const AbbrevPair* p;
|
||||||
for (p = kSubstitutionList; p->abbrev != nullptr; ++p) {
|
for (p = kSubstitutionList; p->abbrev != nullptr; ++p) {
|
||||||
if (state->mangled_cur[0] == p->abbrev[1]) {
|
if (state->mangled_cur[0] == p->abbrev[1]) {
|
||||||
MaybeAppend(state, "std");
|
MaybeAppend(state, "std");
|
||||||
@ -1312,7 +1273,7 @@ static bool ParseSubstitution(State *state) {
|
|||||||
|
|
||||||
// Parse <mangled-name>, optionally followed by either a function-clone suffix
|
// Parse <mangled-name>, optionally followed by either a function-clone suffix
|
||||||
// or version suffix. Returns true only if all of "mangled_cur" was consumed.
|
// or version suffix. Returns true only if all of "mangled_cur" was consumed.
|
||||||
static bool ParseTopLevelMangledName(State *state) {
|
static bool ParseTopLevelMangledName(State* state) {
|
||||||
if (ParseMangledName(state)) {
|
if (ParseMangledName(state)) {
|
||||||
if (state->mangled_cur[0] != '\0') {
|
if (state->mangled_cur[0] != '\0') {
|
||||||
// Drop trailing function clone suffix, if any.
|
// Drop trailing function clone suffix, if any.
|
||||||
@ -1334,9 +1295,9 @@ static bool ParseTopLevelMangledName(State *state) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// The demangler entry point.
|
// The demangler entry point.
|
||||||
bool Demangle(const char *mangled, char *out, size_t out_size) {
|
bool Demangle(const char* mangled, char* out, size_t out_size) {
|
||||||
#if defined(GLOG_OS_WINDOWS)
|
#if defined(GLOG_OS_WINDOWS)
|
||||||
#if defined(HAVE_DBGHELP)
|
# if defined(HAVE_DBGHELP)
|
||||||
// When built with incremental linking, the Windows debugger
|
// When built with incremental linking, the Windows debugger
|
||||||
// library provides a more complicated `Symbol->Name` with the
|
// library provides a more complicated `Symbol->Name` with the
|
||||||
// Incremental Linking Table offset, which looks like
|
// Incremental Linking Table offset, which looks like
|
||||||
@ -1347,23 +1308,23 @@ bool Demangle(const char *mangled, char *out, size_t out_size) {
|
|||||||
//
|
//
|
||||||
// Since we may be in a signal handler here, we cannot use `std::string`.
|
// Since we may be in a signal handler here, we cannot use `std::string`.
|
||||||
char buffer[1024]; // Big enough for a sane symbol.
|
char buffer[1024]; // Big enough for a sane symbol.
|
||||||
const char *lparen = strchr(mangled, '(');
|
const char* lparen = strchr(mangled, '(');
|
||||||
if (lparen) {
|
if (lparen) {
|
||||||
// Extract the string `(?...)`
|
// Extract the string `(?...)`
|
||||||
const char *rparen = strchr(lparen, ')');
|
const char* rparen = strchr(lparen, ')');
|
||||||
size_t length = static_cast<size_t>(rparen - lparen) - 1;
|
size_t length = static_cast<size_t>(rparen - lparen) - 1;
|
||||||
strncpy(buffer, lparen + 1, length);
|
strncpy(buffer, lparen + 1, length);
|
||||||
buffer[length] = '\0';
|
buffer[length] = '\0';
|
||||||
mangled = buffer;
|
mangled = buffer;
|
||||||
} // Else the symbol wasn't inside a set of parentheses
|
} // Else the symbol wasn't inside a set of parentheses
|
||||||
// We use the ANSI version to ensure the string type is always `char *`.
|
// We use the ANSI version to ensure the string type is always `char *`.
|
||||||
return UnDecorateSymbolName(mangled, out, out_size, UNDNAME_COMPLETE);
|
return UnDecorateSymbolName(mangled, out, out_size, UNDNAME_COMPLETE);
|
||||||
#else
|
# else
|
||||||
(void)mangled;
|
(void)mangled;
|
||||||
(void)out;
|
(void)out;
|
||||||
(void)out_size;
|
(void)out_size;
|
||||||
return false;
|
return false;
|
||||||
#endif
|
# endif
|
||||||
#else
|
#else
|
||||||
State state;
|
State state;
|
||||||
InitState(&state, mangled, out, out_size);
|
InitState(&state, mangled, out, out_size);
|
||||||
|
|||||||
@ -78,7 +78,7 @@ namespace google {
|
|||||||
// Demangle "mangled". On success, return true and write the
|
// Demangle "mangled". On success, return true and write the
|
||||||
// demangled symbol name to "out". Otherwise, return false.
|
// demangled symbol name to "out". Otherwise, return false.
|
||||||
// "out" is modified even if demangling is unsuccessful.
|
// "out" is modified even if demangling is unsuccessful.
|
||||||
bool GLOG_EXPORT Demangle(const char *mangled, char *out, size_t out_size);
|
bool GLOG_EXPORT Demangle(const char* mangled, char* out, size_t out_size);
|
||||||
|
|
||||||
} // namespace google
|
} // namespace google
|
||||||
|
|
||||||
|
|||||||
@ -43,7 +43,7 @@
|
|||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
|
||||||
#ifdef GLOG_USE_GFLAGS
|
#ifdef GLOG_USE_GFLAGS
|
||||||
#include <gflags/gflags.h>
|
# include <gflags/gflags.h>
|
||||||
using namespace GFLAGS_NAMESPACE;
|
using namespace GFLAGS_NAMESPACE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ using namespace std;
|
|||||||
using namespace google;
|
using namespace google;
|
||||||
|
|
||||||
// A wrapper function for Demangle() to make the unit test simple.
|
// A wrapper function for Demangle() to make the unit test simple.
|
||||||
static const char *DemangleIt(const char * const mangled) {
|
static const char* DemangleIt(const char* const mangled) {
|
||||||
static char demangled[4096];
|
static char demangled[4096];
|
||||||
if (Demangle(mangled, demangled, sizeof(demangled))) {
|
if (Demangle(mangled, demangled, sizeof(demangled))) {
|
||||||
return demangled;
|
return demangled;
|
||||||
@ -65,28 +65,25 @@ static const char *DemangleIt(const char * const mangled) {
|
|||||||
|
|
||||||
#if defined(GLOG_OS_WINDOWS)
|
#if defined(GLOG_OS_WINDOWS)
|
||||||
|
|
||||||
#if defined(HAVE_DBGHELP) && !defined(NDEBUG)
|
# if defined(HAVE_DBGHELP) && !defined(NDEBUG)
|
||||||
TEST(Demangle, Windows) {
|
TEST(Demangle, Windows) {
|
||||||
EXPECT_STREQ(
|
EXPECT_STREQ("public: static void __cdecl Foo::func(int)",
|
||||||
"public: static void __cdecl Foo::func(int)",
|
DemangleIt("?func@Foo@@SAXH@Z"));
|
||||||
DemangleIt("?func@Foo@@SAXH@Z"));
|
EXPECT_STREQ("public: static void __cdecl Foo::func(int)",
|
||||||
EXPECT_STREQ(
|
DemangleIt("@ILT+1105(?func@Foo@@SAXH@Z)"));
|
||||||
"public: static void __cdecl Foo::func(int)",
|
EXPECT_STREQ("int __cdecl foobarArray(int * const)",
|
||||||
DemangleIt("@ILT+1105(?func@Foo@@SAXH@Z)"));
|
DemangleIt("?foobarArray@@YAHQAH@Z"));
|
||||||
EXPECT_STREQ(
|
|
||||||
"int __cdecl foobarArray(int * const)",
|
|
||||||
DemangleIt("?foobarArray@@YAHQAH@Z"));
|
|
||||||
}
|
}
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
// Test corner cases of boundary conditions.
|
// Test corner cases of boundary conditions.
|
||||||
TEST(Demangle, CornerCases) {
|
TEST(Demangle, CornerCases) {
|
||||||
const size_t size = 10;
|
const size_t size = 10;
|
||||||
char tmp[size] = { 0 };
|
char tmp[size] = {0};
|
||||||
const char *demangled = "foobar()";
|
const char* demangled = "foobar()";
|
||||||
const char *mangled = "_Z6foobarv";
|
const char* mangled = "_Z6foobarv";
|
||||||
EXPECT_TRUE(Demangle(mangled, tmp, sizeof(tmp)));
|
EXPECT_TRUE(Demangle(mangled, tmp, sizeof(tmp)));
|
||||||
// sizeof("foobar()") == size - 1
|
// sizeof("foobar()") == size - 1
|
||||||
EXPECT_STREQ(demangled, tmp);
|
EXPECT_STREQ(demangled, tmp);
|
||||||
@ -147,7 +144,7 @@ TEST(Demangle, FromFile) {
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char** argv) {
|
||||||
#ifdef GLOG_USE_GFLAGS
|
#ifdef GLOG_USE_GFLAGS
|
||||||
ParseCommandLineFlags(&argc, &argv, true);
|
ParseCommandLineFlags(&argc, &argv, true);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
#include "demangle.h"
|
#include "demangle.h"
|
||||||
|
|
||||||
extern "C" int LLVMFuzzerTestOneInput(const unsigned char *Data,
|
extern "C" int LLVMFuzzerTestOneInput(const unsigned char* Data,
|
||||||
unsigned Size) {
|
unsigned Size) {
|
||||||
if (Size >= 4095) {
|
if (Size >= 4095) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@ -51,20 +51,20 @@
|
|||||||
using LogSeverity = int;
|
using LogSeverity = int;
|
||||||
|
|
||||||
const int GLOG_INFO = 0, GLOG_WARNING = 1, GLOG_ERROR = 2, GLOG_FATAL = 3,
|
const int GLOG_INFO = 0, GLOG_WARNING = 1, GLOG_ERROR = 2, GLOG_FATAL = 3,
|
||||||
NUM_SEVERITIES = 4;
|
NUM_SEVERITIES = 4;
|
||||||
#ifndef GLOG_NO_ABBREVIATED_SEVERITIES
|
#ifndef GLOG_NO_ABBREVIATED_SEVERITIES
|
||||||
# ifdef ERROR
|
# ifdef ERROR
|
||||||
# error ERROR macro is defined. Define GLOG_NO_ABBREVIATED_SEVERITIES before including logging.h. See the document for detail.
|
# error ERROR macro is defined. Define GLOG_NO_ABBREVIATED_SEVERITIES before including logging.h. See the document for detail.
|
||||||
# endif
|
# endif
|
||||||
const int INFO = GLOG_INFO, WARNING = GLOG_WARNING,
|
const int INFO = GLOG_INFO, WARNING = GLOG_WARNING, ERROR = GLOG_ERROR,
|
||||||
ERROR = GLOG_ERROR, FATAL = GLOG_FATAL;
|
FATAL = GLOG_FATAL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// DFATAL is FATAL in debug mode, ERROR in normal mode
|
// DFATAL is FATAL in debug mode, ERROR in normal mode
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
#define DFATAL_LEVEL ERROR
|
# define DFATAL_LEVEL ERROR
|
||||||
#else
|
#else
|
||||||
#define DFATAL_LEVEL FATAL
|
# define DFATAL_LEVEL FATAL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern GLOG_EXPORT const char* const LogSeverityNames[NUM_SEVERITIES];
|
extern GLOG_EXPORT const char* const LogSeverityNames[NUM_SEVERITIES];
|
||||||
@ -89,10 +89,10 @@ extern GLOG_EXPORT const char* const LogSeverityNames[NUM_SEVERITIES];
|
|||||||
//
|
//
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
enum { DEBUG_MODE = 0 };
|
enum { DEBUG_MODE = 0 };
|
||||||
#define IF_DEBUG_MODE(x)
|
# define IF_DEBUG_MODE(x)
|
||||||
#else
|
#else
|
||||||
enum { DEBUG_MODE = 1 };
|
enum { DEBUG_MODE = 1 };
|
||||||
#define IF_DEBUG_MODE(x) x
|
# define IF_DEBUG_MODE(x) x
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // BASE_LOG_SEVERITY_H__
|
#endif // BASE_LOG_SEVERITY_H__
|
||||||
|
|||||||
@ -50,28 +50,28 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
#define GLOG_MSVC_PUSH_DISABLE_WARNING(n) \
|
# define GLOG_MSVC_PUSH_DISABLE_WARNING(n) \
|
||||||
__pragma(warning(push)) __pragma(warning(disable : n))
|
__pragma(warning(push)) __pragma(warning(disable : n))
|
||||||
#define GLOG_MSVC_POP_WARNING() __pragma(warning(pop))
|
# define GLOG_MSVC_POP_WARNING() __pragma(warning(pop))
|
||||||
#else
|
#else
|
||||||
#define GLOG_MSVC_PUSH_DISABLE_WARNING(n)
|
# define GLOG_MSVC_PUSH_DISABLE_WARNING(n)
|
||||||
#define GLOG_MSVC_POP_WARNING()
|
# define GLOG_MSVC_POP_WARNING()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "glog/platform.h"
|
#include "glog/platform.h"
|
||||||
|
|
||||||
#if defined(__has_attribute)
|
#if defined(__has_attribute)
|
||||||
#if __has_attribute(used)
|
# if __has_attribute(used)
|
||||||
#define GLOG_USED __attribute__((used))
|
# define GLOG_USED __attribute__((used))
|
||||||
#endif // __has_attribute(used)
|
# endif // __has_attribute(used)
|
||||||
#endif // defined(__has_attribute)
|
#endif // defined(__has_attribute)
|
||||||
|
|
||||||
#if !defined(GLOG_USED)
|
#if !defined(GLOG_USED)
|
||||||
#define GLOG_USED
|
# define GLOG_USED
|
||||||
#endif // !defined(GLOG_USED)
|
#endif // !defined(GLOG_USED)
|
||||||
|
|
||||||
#if defined(GLOG_USE_GLOG_EXPORT)
|
#if defined(GLOG_USE_GLOG_EXPORT)
|
||||||
#include "glog/export.h"
|
# include "glog/export.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// We care a lot about number of bits things take up. Unfortunately,
|
// We care a lot about number of bits things take up. Unfortunately,
|
||||||
@ -83,7 +83,7 @@
|
|||||||
#include <cstdint> // the normal place uint16_t is defined
|
#include <cstdint> // the normal place uint16_t is defined
|
||||||
|
|
||||||
#if defined(GLOG_USE_GFLAGS)
|
#if defined(GLOG_USE_GFLAGS)
|
||||||
#include <gflags/gflags.h>
|
# include <gflags/gflags.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
@ -158,7 +158,7 @@ typedef void (*CustomPrefixCallback)(std::ostream& s, const LogMessageInfo& l,
|
|||||||
// file, add "#define GOOGLE_STRIP_LOG 1" to that file _before_ including
|
// file, add "#define GOOGLE_STRIP_LOG 1" to that file _before_ including
|
||||||
// base/logging.h
|
// base/logging.h
|
||||||
#ifndef GOOGLE_STRIP_LOG
|
#ifndef GOOGLE_STRIP_LOG
|
||||||
#define GOOGLE_STRIP_LOG 0
|
# define GOOGLE_STRIP_LOG 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// GCC can be told that a certain branch is not likely to be taken (for
|
// GCC can be told that a certain branch is not likely to be taken (for
|
||||||
@ -167,43 +167,43 @@ typedef void (*CustomPrefixCallback)(std::ostream& s, const LogMessageInfo& l,
|
|||||||
// the absence of better information (ie. -fprofile-arcs).
|
// the absence of better information (ie. -fprofile-arcs).
|
||||||
//
|
//
|
||||||
#if defined(__has_builtin)
|
#if defined(__has_builtin)
|
||||||
#if __has_builtin(__builtin_expect)
|
# if __has_builtin(__builtin_expect)
|
||||||
#define GLOG_BUILTIN_EXPECT_PRESENT
|
# define GLOG_BUILTIN_EXPECT_PRESENT
|
||||||
#endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(GLOG_BUILTIN_EXPECT_PRESENT) && defined(__GNUG__)
|
#if !defined(GLOG_BUILTIN_EXPECT_PRESENT) && defined(__GNUG__)
|
||||||
// __has_builtin is not available prior to GCC 10
|
// __has_builtin is not available prior to GCC 10
|
||||||
#define GLOG_BUILTIN_EXPECT_PRESENT
|
# define GLOG_BUILTIN_EXPECT_PRESENT
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(GLOG_BUILTIN_EXPECT_PRESENT)
|
#if defined(GLOG_BUILTIN_EXPECT_PRESENT)
|
||||||
|
|
||||||
#ifndef GOOGLE_PREDICT_BRANCH_NOT_TAKEN
|
# ifndef GOOGLE_PREDICT_BRANCH_NOT_TAKEN
|
||||||
#define GOOGLE_PREDICT_BRANCH_NOT_TAKEN(x) (__builtin_expect(x, 0))
|
# define GOOGLE_PREDICT_BRANCH_NOT_TAKEN(x) (__builtin_expect(x, 0))
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
#ifndef GOOGLE_PREDICT_FALSE
|
# ifndef GOOGLE_PREDICT_FALSE
|
||||||
#define GOOGLE_PREDICT_FALSE(x) (__builtin_expect(x, 0))
|
# define GOOGLE_PREDICT_FALSE(x) (__builtin_expect(x, 0))
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
#ifndef GOOGLE_PREDICT_TRUE
|
# ifndef GOOGLE_PREDICT_TRUE
|
||||||
#define GOOGLE_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
|
# define GOOGLE_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#ifndef GOOGLE_PREDICT_BRANCH_NOT_TAKEN
|
# ifndef GOOGLE_PREDICT_BRANCH_NOT_TAKEN
|
||||||
#define GOOGLE_PREDICT_BRANCH_NOT_TAKEN(x) x
|
# define GOOGLE_PREDICT_BRANCH_NOT_TAKEN(x) x
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
#ifndef GOOGLE_PREDICT_TRUE
|
# ifndef GOOGLE_PREDICT_TRUE
|
||||||
#define GOOGLE_PREDICT_FALSE(x) x
|
# define GOOGLE_PREDICT_FALSE(x) x
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
#ifndef GOOGLE_PREDICT_TRUE
|
# ifndef GOOGLE_PREDICT_TRUE
|
||||||
#define GOOGLE_PREDICT_TRUE(x) x
|
# define GOOGLE_PREDICT_TRUE(x) x
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -370,50 +370,51 @@ typedef void (*CustomPrefixCallback)(std::ostream& s, const LogMessageInfo& l,
|
|||||||
#pragma push_macro("DECLARE_uint32")
|
#pragma push_macro("DECLARE_uint32")
|
||||||
|
|
||||||
#ifdef DECLARE_VARIABLE
|
#ifdef DECLARE_VARIABLE
|
||||||
#undef DECLARE_VARIABLE
|
# undef DECLARE_VARIABLE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef DECLARE_bool
|
#ifdef DECLARE_bool
|
||||||
#undef DECLARE_bool
|
# undef DECLARE_bool
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef DECLARE_string
|
#ifdef DECLARE_string
|
||||||
#undef DECLARE_string
|
# undef DECLARE_string
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef DECLARE_int32
|
#ifdef DECLARE_int32
|
||||||
#undef DECLARE_int32
|
# undef DECLARE_int32
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef DECLARE_uint32
|
#ifdef DECLARE_uint32
|
||||||
#undef DECLARE_uint32
|
# undef DECLARE_uint32
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef DECLARE_VARIABLE
|
#ifndef DECLARE_VARIABLE
|
||||||
#define DECLARE_VARIABLE(type, shorttype, name, tn) \
|
# define DECLARE_VARIABLE(type, shorttype, name, tn) \
|
||||||
namespace fL##shorttype { \
|
namespace fL##shorttype { \
|
||||||
extern GLOG_EXPORT type FLAGS_##name; \
|
extern GLOG_EXPORT type FLAGS_##name; \
|
||||||
} \
|
} \
|
||||||
using fL##shorttype::FLAGS_##name
|
using fL##shorttype::FLAGS_##name
|
||||||
|
|
||||||
// bool specialization
|
// bool specialization
|
||||||
#define DECLARE_bool(name) DECLARE_VARIABLE(bool, B, name, bool)
|
# define DECLARE_bool(name) DECLARE_VARIABLE(bool, B, name, bool)
|
||||||
|
|
||||||
// int32 specialization
|
// int32 specialization
|
||||||
#define DECLARE_int32(name) DECLARE_VARIABLE(google::int32, I, name, int32)
|
# define DECLARE_int32(name) DECLARE_VARIABLE(google::int32, I, name, int32)
|
||||||
|
|
||||||
#if !defined(DECLARE_uint32)
|
# if !defined(DECLARE_uint32)
|
||||||
// uint32 specialization
|
// uint32 specialization
|
||||||
#define DECLARE_uint32(name) DECLARE_VARIABLE(google::uint32, U, name, uint32)
|
# define DECLARE_uint32(name) \
|
||||||
#endif // !defined(DECLARE_uint32) && !defined(GLOG_USE_GFLAGS)
|
DECLARE_VARIABLE(google::uint32, U, name, uint32)
|
||||||
|
# endif // !defined(DECLARE_uint32) && !defined(GLOG_USE_GFLAGS)
|
||||||
|
|
||||||
// Special case for string, because we have to specify the namespace
|
// Special case for string, because we have to specify the namespace
|
||||||
// std::string, which doesn't play nicely with our FLAG__namespace hackery.
|
// std::string, which doesn't play nicely with our FLAG__namespace hackery.
|
||||||
#define DECLARE_string(name) \
|
# define DECLARE_string(name) \
|
||||||
namespace fLS { \
|
namespace fLS { \
|
||||||
extern GLOG_EXPORT std::string& FLAGS_##name; \
|
extern GLOG_EXPORT std::string& FLAGS_##name; \
|
||||||
} \
|
} \
|
||||||
using fLS::FLAGS_##name
|
using fLS::FLAGS_##name
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Set whether appending a timestamp to the log file name
|
// Set whether appending a timestamp to the log file name
|
||||||
@ -493,58 +494,58 @@ DECLARE_string(logmailer);
|
|||||||
// better to have compact code for these operations.
|
// better to have compact code for these operations.
|
||||||
|
|
||||||
#if GOOGLE_STRIP_LOG == 0
|
#if GOOGLE_STRIP_LOG == 0
|
||||||
#define COMPACT_GOOGLE_LOG_INFO google::LogMessage(__FILE__, __LINE__)
|
# define COMPACT_GOOGLE_LOG_INFO google::LogMessage(__FILE__, __LINE__)
|
||||||
#define LOG_TO_STRING_INFO(message) \
|
# define LOG_TO_STRING_INFO(message) \
|
||||||
google::LogMessage(__FILE__, __LINE__, google::GLOG_INFO, message)
|
google::LogMessage(__FILE__, __LINE__, google::GLOG_INFO, message)
|
||||||
#else
|
#else
|
||||||
#define COMPACT_GOOGLE_LOG_INFO google::NullStream()
|
# define COMPACT_GOOGLE_LOG_INFO google::NullStream()
|
||||||
#define LOG_TO_STRING_INFO(message) google::NullStream()
|
# define LOG_TO_STRING_INFO(message) google::NullStream()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if GOOGLE_STRIP_LOG <= 1
|
#if GOOGLE_STRIP_LOG <= 1
|
||||||
#define COMPACT_GOOGLE_LOG_WARNING \
|
# define COMPACT_GOOGLE_LOG_WARNING \
|
||||||
google::LogMessage(__FILE__, __LINE__, google::GLOG_WARNING)
|
google::LogMessage(__FILE__, __LINE__, google::GLOG_WARNING)
|
||||||
#define LOG_TO_STRING_WARNING(message) \
|
# define LOG_TO_STRING_WARNING(message) \
|
||||||
google::LogMessage(__FILE__, __LINE__, google::GLOG_WARNING, message)
|
google::LogMessage(__FILE__, __LINE__, google::GLOG_WARNING, message)
|
||||||
#else
|
#else
|
||||||
#define COMPACT_GOOGLE_LOG_WARNING google::NullStream()
|
# define COMPACT_GOOGLE_LOG_WARNING google::NullStream()
|
||||||
#define LOG_TO_STRING_WARNING(message) google::NullStream()
|
# define LOG_TO_STRING_WARNING(message) google::NullStream()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if GOOGLE_STRIP_LOG <= 2
|
#if GOOGLE_STRIP_LOG <= 2
|
||||||
#define COMPACT_GOOGLE_LOG_ERROR \
|
# define COMPACT_GOOGLE_LOG_ERROR \
|
||||||
google::LogMessage(__FILE__, __LINE__, google::GLOG_ERROR)
|
google::LogMessage(__FILE__, __LINE__, google::GLOG_ERROR)
|
||||||
#define LOG_TO_STRING_ERROR(message) \
|
# define LOG_TO_STRING_ERROR(message) \
|
||||||
google::LogMessage(__FILE__, __LINE__, google::GLOG_ERROR, message)
|
google::LogMessage(__FILE__, __LINE__, google::GLOG_ERROR, message)
|
||||||
#else
|
#else
|
||||||
#define COMPACT_GOOGLE_LOG_ERROR google::NullStream()
|
# define COMPACT_GOOGLE_LOG_ERROR google::NullStream()
|
||||||
#define LOG_TO_STRING_ERROR(message) google::NullStream()
|
# define LOG_TO_STRING_ERROR(message) google::NullStream()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if GOOGLE_STRIP_LOG <= 3
|
#if GOOGLE_STRIP_LOG <= 3
|
||||||
#define COMPACT_GOOGLE_LOG_FATAL google::LogMessageFatal(__FILE__, __LINE__)
|
# define COMPACT_GOOGLE_LOG_FATAL google::LogMessageFatal(__FILE__, __LINE__)
|
||||||
#define LOG_TO_STRING_FATAL(message) \
|
# define LOG_TO_STRING_FATAL(message) \
|
||||||
google::LogMessage(__FILE__, __LINE__, google::GLOG_FATAL, message)
|
google::LogMessage(__FILE__, __LINE__, google::GLOG_FATAL, message)
|
||||||
#else
|
#else
|
||||||
#define COMPACT_GOOGLE_LOG_FATAL google::NullStreamFatal()
|
# define COMPACT_GOOGLE_LOG_FATAL google::NullStreamFatal()
|
||||||
#define LOG_TO_STRING_FATAL(message) google::NullStreamFatal()
|
# define LOG_TO_STRING_FATAL(message) google::NullStreamFatal()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
|
#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
|
||||||
#define DCHECK_IS_ON() 0
|
# define DCHECK_IS_ON() 0
|
||||||
#else
|
#else
|
||||||
#define DCHECK_IS_ON() 1
|
# define DCHECK_IS_ON() 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// For DFATAL, we want to use LogMessage (as opposed to
|
// For DFATAL, we want to use LogMessage (as opposed to
|
||||||
// LogMessageFatal), to be consistent with the original behavior.
|
// LogMessageFatal), to be consistent with the original behavior.
|
||||||
#if !DCHECK_IS_ON()
|
#if !DCHECK_IS_ON()
|
||||||
#define COMPACT_GOOGLE_LOG_DFATAL COMPACT_GOOGLE_LOG_ERROR
|
# define COMPACT_GOOGLE_LOG_DFATAL COMPACT_GOOGLE_LOG_ERROR
|
||||||
#elif GOOGLE_STRIP_LOG <= 3
|
#elif GOOGLE_STRIP_LOG <= 3
|
||||||
#define COMPACT_GOOGLE_LOG_DFATAL \
|
# define COMPACT_GOOGLE_LOG_DFATAL \
|
||||||
google::LogMessage(__FILE__, __LINE__, google::GLOG_FATAL)
|
google::LogMessage(__FILE__, __LINE__, google::GLOG_FATAL)
|
||||||
#else
|
#else
|
||||||
#define COMPACT_GOOGLE_LOG_DFATAL google::NullStreamFatal()
|
# define COMPACT_GOOGLE_LOG_DFATAL google::NullStreamFatal()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define GOOGLE_LOG_INFO(counter) \
|
#define GOOGLE_LOG_INFO(counter) \
|
||||||
@ -581,22 +582,22 @@ DECLARE_string(logmailer);
|
|||||||
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || \
|
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || \
|
||||||
defined(__CYGWIN__) || defined(__CYGWIN32__)
|
defined(__CYGWIN__) || defined(__CYGWIN32__)
|
||||||
// A very useful logging macro to log windows errors:
|
// A very useful logging macro to log windows errors:
|
||||||
#define LOG_SYSRESULT(result) \
|
# define LOG_SYSRESULT(result) \
|
||||||
if (FAILED(HRESULT_FROM_WIN32(result))) { \
|
if (FAILED(HRESULT_FROM_WIN32(result))) { \
|
||||||
LPSTR message = nullptr; \
|
LPSTR message = nullptr; \
|
||||||
LPSTR msg = reinterpret_cast<LPSTR>(&message); \
|
LPSTR msg = reinterpret_cast<LPSTR>(&message); \
|
||||||
DWORD message_length = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | \
|
DWORD message_length = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | \
|
||||||
FORMAT_MESSAGE_FROM_SYSTEM | \
|
FORMAT_MESSAGE_FROM_SYSTEM | \
|
||||||
FORMAT_MESSAGE_IGNORE_INSERTS, \
|
FORMAT_MESSAGE_IGNORE_INSERTS, \
|
||||||
0, result, 0, msg, 100, nullptr); \
|
0, result, 0, msg, 100, nullptr); \
|
||||||
if (message_length > 0) { \
|
if (message_length > 0) { \
|
||||||
google::LogMessage(__FILE__, __LINE__, google::GLOG_ERROR, 0, \
|
google::LogMessage(__FILE__, __LINE__, google::GLOG_ERROR, 0, \
|
||||||
&google::LogMessage::SendToLog) \
|
&google::LogMessage::SendToLog) \
|
||||||
.stream() \
|
.stream() \
|
||||||
<< reinterpret_cast<const char*>(message); \
|
<< reinterpret_cast<const char*>(message); \
|
||||||
LocalFree(message); \
|
LocalFree(message); \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// We use the preprocessor's merging operator, "##", so that, e.g.,
|
// We use the preprocessor's merging operator, "##", so that, e.g.,
|
||||||
@ -781,9 +782,9 @@ GLOG_EXPORT void MakeCheckOpValueString(std::ostream* os,
|
|||||||
template <typename T1, typename T2>
|
template <typename T1, typename T2>
|
||||||
std::string* MakeCheckOpString(const T1& v1, const T2& v2, const char* exprtext)
|
std::string* MakeCheckOpString(const T1& v1, const T2& v2, const char* exprtext)
|
||||||
#if defined(__has_attribute)
|
#if defined(__has_attribute)
|
||||||
#if __has_attribute(used)
|
# if __has_attribute(used)
|
||||||
__attribute__((noinline))
|
__attribute__((noinline))
|
||||||
#endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -866,7 +867,7 @@ DEFINE_CHECK_OP_IMPL(Check_GT, >)
|
|||||||
|
|
||||||
#if defined(STATIC_ANALYSIS)
|
#if defined(STATIC_ANALYSIS)
|
||||||
// Only for static analysis tool to know that it is equivalent to assert
|
// Only for static analysis tool to know that it is equivalent to assert
|
||||||
#define CHECK_OP_LOG(name, op, val1, val2, log) CHECK((val1)op(val2))
|
# define CHECK_OP_LOG(name, op, val1, val2, log) CHECK((val1)op(val2))
|
||||||
#elif DCHECK_IS_ON()
|
#elif DCHECK_IS_ON()
|
||||||
// In debug mode, avoid constructing CheckOpStrings if possible,
|
// In debug mode, avoid constructing CheckOpStrings if possible,
|
||||||
// to reduce the overhead of CHECK statements by 2x.
|
// to reduce the overhead of CHECK statements by 2x.
|
||||||
@ -878,27 +879,27 @@ DEFINE_CHECK_OP_IMPL(Check_GT, >)
|
|||||||
// file is included). Save the current meaning now and use it
|
// file is included). Save the current meaning now and use it
|
||||||
// in the macro.
|
// in the macro.
|
||||||
typedef std::string _Check_string;
|
typedef std::string _Check_string;
|
||||||
#define CHECK_OP_LOG(name, op, val1, val2, log) \
|
# define CHECK_OP_LOG(name, op, val1, val2, log) \
|
||||||
while (google::_Check_string* _result = google::Check##name##Impl( \
|
while (google::_Check_string* _result = google::Check##name##Impl( \
|
||||||
google::GetReferenceableValue(val1), \
|
google::GetReferenceableValue(val1), \
|
||||||
google::GetReferenceableValue(val2), #val1 " " #op " " #val2)) \
|
google::GetReferenceableValue(val2), #val1 " " #op " " #val2)) \
|
||||||
log(__FILE__, __LINE__, google::CheckOpString(_result)).stream()
|
log(__FILE__, __LINE__, google::CheckOpString(_result)).stream()
|
||||||
#else
|
#else
|
||||||
// In optimized mode, use CheckOpString to hint to compiler that
|
// In optimized mode, use CheckOpString to hint to compiler that
|
||||||
// the while condition is unlikely.
|
// the while condition is unlikely.
|
||||||
#define CHECK_OP_LOG(name, op, val1, val2, log) \
|
# define CHECK_OP_LOG(name, op, val1, val2, log) \
|
||||||
while (google::CheckOpString _result = google::Check##name##Impl( \
|
while (google::CheckOpString _result = google::Check##name##Impl( \
|
||||||
google::GetReferenceableValue(val1), \
|
google::GetReferenceableValue(val1), \
|
||||||
google::GetReferenceableValue(val2), #val1 " " #op " " #val2)) \
|
google::GetReferenceableValue(val2), #val1 " " #op " " #val2)) \
|
||||||
log(__FILE__, __LINE__, _result).stream()
|
log(__FILE__, __LINE__, _result).stream()
|
||||||
#endif // STATIC_ANALYSIS, DCHECK_IS_ON()
|
#endif // STATIC_ANALYSIS, DCHECK_IS_ON()
|
||||||
|
|
||||||
#if GOOGLE_STRIP_LOG <= 3
|
#if GOOGLE_STRIP_LOG <= 3
|
||||||
#define CHECK_OP(name, op, val1, val2) \
|
# define CHECK_OP(name, op, val1, val2) \
|
||||||
CHECK_OP_LOG(name, op, val1, val2, google::LogMessageFatal)
|
CHECK_OP_LOG(name, op, val1, val2, google::LogMessageFatal)
|
||||||
#else
|
#else
|
||||||
#define CHECK_OP(name, op, val1, val2) \
|
# define CHECK_OP(name, op, val1, val2) \
|
||||||
CHECK_OP_LOG(name, op, val1, val2, google::NullStreamFatal)
|
CHECK_OP_LOG(name, op, val1, val2, google::NullStreamFatal)
|
||||||
#endif // STRIP_LOG <= 3
|
#endif // STRIP_LOG <= 3
|
||||||
|
|
||||||
// Equality/Inequality checks - compare two values, and log a FATAL message
|
// Equality/Inequality checks - compare two values, and log a FATAL message
|
||||||
@ -1028,20 +1029,20 @@ DECLARE_CHECK_STROP_IMPL(strcasecmp, false)
|
|||||||
#define LOG_PREVIOUS_TIME LOG_EVERY_N_VARNAME(previousTime_, __LINE__)
|
#define LOG_PREVIOUS_TIME LOG_EVERY_N_VARNAME(previousTime_, __LINE__)
|
||||||
|
|
||||||
#if defined(__has_feature)
|
#if defined(__has_feature)
|
||||||
#if __has_feature(thread_sanitizer)
|
# if __has_feature(thread_sanitizer)
|
||||||
#define GLOG_SANITIZE_THREAD 1
|
# define GLOG_SANITIZE_THREAD 1
|
||||||
#endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(GLOG_SANITIZE_THREAD) && defined(__SANITIZE_THREAD__) && \
|
#if !defined(GLOG_SANITIZE_THREAD) && defined(__SANITIZE_THREAD__) && \
|
||||||
__SANITIZE_THREAD__
|
__SANITIZE_THREAD__
|
||||||
#define GLOG_SANITIZE_THREAD 1
|
# define GLOG_SANITIZE_THREAD 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(GLOG_SANITIZE_THREAD)
|
#if defined(GLOG_SANITIZE_THREAD)
|
||||||
#define GLOG_IFDEF_THREAD_SANITIZER(X) X
|
# define GLOG_IFDEF_THREAD_SANITIZER(X) X
|
||||||
#else
|
#else
|
||||||
#define GLOG_IFDEF_THREAD_SANITIZER(X)
|
# define GLOG_IFDEF_THREAD_SANITIZER(X)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(GLOG_SANITIZE_THREAD)
|
#if defined(GLOG_SANITIZE_THREAD)
|
||||||
@ -1166,9 +1167,9 @@ enum PRIVATE_Counter { COUNTER };
|
|||||||
// substituted with 0, and it expands to COMPACT_GOOGLE_LOG_0. To allow us
|
// substituted with 0, and it expands to COMPACT_GOOGLE_LOG_0. To allow us
|
||||||
// to keep using this syntax, we define this macro to do the same thing
|
// to keep using this syntax, we define this macro to do the same thing
|
||||||
// as COMPACT_GOOGLE_LOG_ERROR.
|
// as COMPACT_GOOGLE_LOG_ERROR.
|
||||||
#define COMPACT_GOOGLE_LOG_0 COMPACT_GOOGLE_LOG_ERROR
|
# define COMPACT_GOOGLE_LOG_0 COMPACT_GOOGLE_LOG_ERROR
|
||||||
#define SYSLOG_0 SYSLOG_ERROR
|
# define SYSLOG_0 SYSLOG_ERROR
|
||||||
#define LOG_TO_STRING_0 LOG_TO_STRING_ERROR
|
# define LOG_TO_STRING_0 LOG_TO_STRING_ERROR
|
||||||
// Needed for LOG_IS_ON(ERROR).
|
// Needed for LOG_IS_ON(ERROR).
|
||||||
const LogSeverity GLOG_0 = GLOG_ERROR;
|
const LogSeverity GLOG_0 = GLOG_ERROR;
|
||||||
#else
|
#else
|
||||||
@ -1176,126 +1177,126 @@ const LogSeverity GLOG_0 = GLOG_ERROR;
|
|||||||
// GLOG_NO_ABBREVIATED_SEVERITIES nor WIN32_LEAN_AND_MEAN.
|
// GLOG_NO_ABBREVIATED_SEVERITIES nor WIN32_LEAN_AND_MEAN.
|
||||||
// For this case, we cannot detect if ERROR is defined before users
|
// For this case, we cannot detect if ERROR is defined before users
|
||||||
// actually use ERROR. Let's make an undefined symbol to warn users.
|
// actually use ERROR. Let's make an undefined symbol to warn users.
|
||||||
#define GLOG_ERROR_MSG \
|
# define GLOG_ERROR_MSG \
|
||||||
ERROR_macro_is_defined_Define_GLOG_NO_ABBREVIATED_SEVERITIES_before_including_logging_h_See_the_document_for_detail
|
ERROR_macro_is_defined_Define_GLOG_NO_ABBREVIATED_SEVERITIES_before_including_logging_h_See_the_document_for_detail
|
||||||
#define COMPACT_GOOGLE_LOG_0 GLOG_ERROR_MSG
|
# define COMPACT_GOOGLE_LOG_0 GLOG_ERROR_MSG
|
||||||
#define SYSLOG_0 GLOG_ERROR_MSG
|
# define SYSLOG_0 GLOG_ERROR_MSG
|
||||||
#define LOG_TO_STRING_0 GLOG_ERROR_MSG
|
# define LOG_TO_STRING_0 GLOG_ERROR_MSG
|
||||||
#define GLOG_0 GLOG_ERROR_MSG
|
# define GLOG_0 GLOG_ERROR_MSG
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Plus some debug-logging macros that get compiled to nothing for production
|
// Plus some debug-logging macros that get compiled to nothing for production
|
||||||
|
|
||||||
#if DCHECK_IS_ON()
|
#if DCHECK_IS_ON()
|
||||||
|
|
||||||
#define DLOG(severity) LOG(severity)
|
# define DLOG(severity) LOG(severity)
|
||||||
#define DVLOG(verboselevel) VLOG(verboselevel)
|
# define DVLOG(verboselevel) VLOG(verboselevel)
|
||||||
#define DLOG_IF(severity, condition) LOG_IF(severity, condition)
|
# define DLOG_IF(severity, condition) LOG_IF(severity, condition)
|
||||||
#define DLOG_EVERY_N(severity, n) LOG_EVERY_N(severity, n)
|
# define DLOG_EVERY_N(severity, n) LOG_EVERY_N(severity, n)
|
||||||
#define DLOG_IF_EVERY_N(severity, condition, n) \
|
# define DLOG_IF_EVERY_N(severity, condition, n) \
|
||||||
LOG_IF_EVERY_N(severity, condition, n)
|
LOG_IF_EVERY_N(severity, condition, n)
|
||||||
#define DLOG_FIRST_N(severity, n) LOG_FIRST_N(severity, n)
|
# define DLOG_FIRST_N(severity, n) LOG_FIRST_N(severity, n)
|
||||||
#define DLOG_EVERY_T(severity, T) LOG_EVERY_T(severity, T)
|
# define DLOG_EVERY_T(severity, T) LOG_EVERY_T(severity, T)
|
||||||
#define DLOG_ASSERT(condition) LOG_ASSERT(condition)
|
# define DLOG_ASSERT(condition) LOG_ASSERT(condition)
|
||||||
|
|
||||||
// debug-only checking. executed if DCHECK_IS_ON().
|
// debug-only checking. executed if DCHECK_IS_ON().
|
||||||
#define DCHECK(condition) CHECK(condition)
|
# define DCHECK(condition) CHECK(condition)
|
||||||
#define DCHECK_EQ(val1, val2) CHECK_EQ(val1, val2)
|
# define DCHECK_EQ(val1, val2) CHECK_EQ(val1, val2)
|
||||||
#define DCHECK_NE(val1, val2) CHECK_NE(val1, val2)
|
# define DCHECK_NE(val1, val2) CHECK_NE(val1, val2)
|
||||||
#define DCHECK_LE(val1, val2) CHECK_LE(val1, val2)
|
# define DCHECK_LE(val1, val2) CHECK_LE(val1, val2)
|
||||||
#define DCHECK_LT(val1, val2) CHECK_LT(val1, val2)
|
# define DCHECK_LT(val1, val2) CHECK_LT(val1, val2)
|
||||||
#define DCHECK_GE(val1, val2) CHECK_GE(val1, val2)
|
# define DCHECK_GE(val1, val2) CHECK_GE(val1, val2)
|
||||||
#define DCHECK_GT(val1, val2) CHECK_GT(val1, val2)
|
# define DCHECK_GT(val1, val2) CHECK_GT(val1, val2)
|
||||||
#define DCHECK_NOTNULL(val) CHECK_NOTNULL(val)
|
# define DCHECK_NOTNULL(val) CHECK_NOTNULL(val)
|
||||||
#define DCHECK_STREQ(str1, str2) CHECK_STREQ(str1, str2)
|
# define DCHECK_STREQ(str1, str2) CHECK_STREQ(str1, str2)
|
||||||
#define DCHECK_STRCASEEQ(str1, str2) CHECK_STRCASEEQ(str1, str2)
|
# define DCHECK_STRCASEEQ(str1, str2) CHECK_STRCASEEQ(str1, str2)
|
||||||
#define DCHECK_STRNE(str1, str2) CHECK_STRNE(str1, str2)
|
# define DCHECK_STRNE(str1, str2) CHECK_STRNE(str1, str2)
|
||||||
#define DCHECK_STRCASENE(str1, str2) CHECK_STRCASENE(str1, str2)
|
# define DCHECK_STRCASENE(str1, str2) CHECK_STRCASENE(str1, str2)
|
||||||
|
|
||||||
#else // !DCHECK_IS_ON()
|
#else // !DCHECK_IS_ON()
|
||||||
|
|
||||||
#define DLOG(severity) \
|
# define DLOG(severity) \
|
||||||
static_cast<void>(0), \
|
static_cast<void>(0), \
|
||||||
true ? (void)0 : google::LogMessageVoidify() & LOG(severity)
|
true ? (void)0 : google::LogMessageVoidify() & LOG(severity)
|
||||||
|
|
||||||
#define DVLOG(verboselevel) \
|
# define DVLOG(verboselevel) \
|
||||||
static_cast<void>(0), (true || !VLOG_IS_ON(verboselevel)) \
|
static_cast<void>(0), (true || !VLOG_IS_ON(verboselevel)) \
|
||||||
? (void)0 \
|
? (void)0 \
|
||||||
: google::LogMessageVoidify() & LOG(INFO)
|
: google::LogMessageVoidify() & LOG(INFO)
|
||||||
|
|
||||||
#define DLOG_IF(severity, condition) \
|
# define DLOG_IF(severity, condition) \
|
||||||
static_cast<void>(0), (true || !(condition)) \
|
static_cast<void>(0), (true || !(condition)) \
|
||||||
? (void)0 \
|
? (void)0 \
|
||||||
: google::LogMessageVoidify() & LOG(severity)
|
: google::LogMessageVoidify() & LOG(severity)
|
||||||
|
|
||||||
#define DLOG_EVERY_N(severity, n) \
|
# define DLOG_EVERY_N(severity, n) \
|
||||||
static_cast<void>(0), \
|
static_cast<void>(0), \
|
||||||
true ? (void)0 : google::LogMessageVoidify() & LOG(severity)
|
true ? (void)0 : google::LogMessageVoidify() & LOG(severity)
|
||||||
|
|
||||||
#define DLOG_IF_EVERY_N(severity, condition, n) \
|
# define DLOG_IF_EVERY_N(severity, condition, n) \
|
||||||
static_cast<void>(0), (true || !(condition)) \
|
static_cast<void>(0), (true || !(condition)) \
|
||||||
? (void)0 \
|
? (void)0 \
|
||||||
: google::LogMessageVoidify() & LOG(severity)
|
: google::LogMessageVoidify() & LOG(severity)
|
||||||
|
|
||||||
#define DLOG_FIRST_N(severity, n) \
|
# define DLOG_FIRST_N(severity, n) \
|
||||||
static_cast<void>(0), \
|
static_cast<void>(0), \
|
||||||
true ? (void)0 : google::LogMessageVoidify() & LOG(severity)
|
true ? (void)0 : google::LogMessageVoidify() & LOG(severity)
|
||||||
|
|
||||||
#define DLOG_EVERY_T(severity, T) \
|
# define DLOG_EVERY_T(severity, T) \
|
||||||
static_cast<void>(0), \
|
static_cast<void>(0), \
|
||||||
true ? (void)0 : google::LogMessageVoidify() & LOG(severity)
|
true ? (void)0 : google::LogMessageVoidify() & LOG(severity)
|
||||||
|
|
||||||
#define DLOG_ASSERT(condition) \
|
# define DLOG_ASSERT(condition) \
|
||||||
static_cast<void>(0), true ? (void)0 : LOG_ASSERT(condition)
|
static_cast<void>(0), true ? (void)0 : LOG_ASSERT(condition)
|
||||||
|
|
||||||
// MSVC warning C4127: conditional expression is constant
|
// MSVC warning C4127: conditional expression is constant
|
||||||
#define DCHECK(condition) \
|
# define DCHECK(condition) \
|
||||||
GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
|
GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
|
||||||
while (false) GLOG_MSVC_POP_WARNING() CHECK(condition)
|
while (false) GLOG_MSVC_POP_WARNING() CHECK(condition)
|
||||||
|
|
||||||
#define DCHECK_EQ(val1, val2) \
|
# define DCHECK_EQ(val1, val2) \
|
||||||
GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
|
GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
|
||||||
while (false) GLOG_MSVC_POP_WARNING() CHECK_EQ(val1, val2)
|
while (false) GLOG_MSVC_POP_WARNING() CHECK_EQ(val1, val2)
|
||||||
|
|
||||||
#define DCHECK_NE(val1, val2) \
|
# define DCHECK_NE(val1, val2) \
|
||||||
GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
|
GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
|
||||||
while (false) GLOG_MSVC_POP_WARNING() CHECK_NE(val1, val2)
|
while (false) GLOG_MSVC_POP_WARNING() CHECK_NE(val1, val2)
|
||||||
|
|
||||||
#define DCHECK_LE(val1, val2) \
|
# define DCHECK_LE(val1, val2) \
|
||||||
GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
|
GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
|
||||||
while (false) GLOG_MSVC_POP_WARNING() CHECK_LE(val1, val2)
|
while (false) GLOG_MSVC_POP_WARNING() CHECK_LE(val1, val2)
|
||||||
|
|
||||||
#define DCHECK_LT(val1, val2) \
|
# define DCHECK_LT(val1, val2) \
|
||||||
GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
|
GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
|
||||||
while (false) GLOG_MSVC_POP_WARNING() CHECK_LT(val1, val2)
|
while (false) GLOG_MSVC_POP_WARNING() CHECK_LT(val1, val2)
|
||||||
|
|
||||||
#define DCHECK_GE(val1, val2) \
|
# define DCHECK_GE(val1, val2) \
|
||||||
GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
|
GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
|
||||||
while (false) GLOG_MSVC_POP_WARNING() CHECK_GE(val1, val2)
|
while (false) GLOG_MSVC_POP_WARNING() CHECK_GE(val1, val2)
|
||||||
|
|
||||||
#define DCHECK_GT(val1, val2) \
|
# define DCHECK_GT(val1, val2) \
|
||||||
GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
|
GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
|
||||||
while (false) GLOG_MSVC_POP_WARNING() CHECK_GT(val1, val2)
|
while (false) GLOG_MSVC_POP_WARNING() CHECK_GT(val1, val2)
|
||||||
|
|
||||||
// You may see warnings in release mode if you don't use the return
|
// You may see warnings in release mode if you don't use the return
|
||||||
// value of DCHECK_NOTNULL. Please just use DCHECK for such cases.
|
// value of DCHECK_NOTNULL. Please just use DCHECK for such cases.
|
||||||
#define DCHECK_NOTNULL(val) (val)
|
# define DCHECK_NOTNULL(val) (val)
|
||||||
|
|
||||||
#define DCHECK_STREQ(str1, str2) \
|
# define DCHECK_STREQ(str1, str2) \
|
||||||
GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
|
GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
|
||||||
while (false) GLOG_MSVC_POP_WARNING() CHECK_STREQ(str1, str2)
|
while (false) GLOG_MSVC_POP_WARNING() CHECK_STREQ(str1, str2)
|
||||||
|
|
||||||
#define DCHECK_STRCASEEQ(str1, str2) \
|
# define DCHECK_STRCASEEQ(str1, str2) \
|
||||||
GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
|
GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
|
||||||
while (false) GLOG_MSVC_POP_WARNING() CHECK_STRCASEEQ(str1, str2)
|
while (false) GLOG_MSVC_POP_WARNING() CHECK_STRCASEEQ(str1, str2)
|
||||||
|
|
||||||
#define DCHECK_STRNE(str1, str2) \
|
# define DCHECK_STRNE(str1, str2) \
|
||||||
GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
|
GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
|
||||||
while (false) GLOG_MSVC_POP_WARNING() CHECK_STRNE(str1, str2)
|
while (false) GLOG_MSVC_POP_WARNING() CHECK_STRNE(str1, str2)
|
||||||
|
|
||||||
#define DCHECK_STRCASENE(str1, str2) \
|
# define DCHECK_STRCASENE(str1, str2) \
|
||||||
GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
|
GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
|
||||||
while (false) GLOG_MSVC_POP_WARNING() CHECK_STRCASENE(str1, str2)
|
while (false) GLOG_MSVC_POP_WARNING() CHECK_STRCASENE(str1, str2)
|
||||||
|
|
||||||
#endif // DCHECK_IS_ON()
|
#endif // DCHECK_IS_ON()
|
||||||
|
|
||||||
|
|||||||
@ -35,26 +35,26 @@
|
|||||||
#define GLOG_PLATFORM_H
|
#define GLOG_PLATFORM_H
|
||||||
|
|
||||||
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
|
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
|
||||||
#define GLOG_OS_WINDOWS
|
# define GLOG_OS_WINDOWS
|
||||||
#elif defined(__CYGWIN__) || defined(__CYGWIN32__)
|
#elif defined(__CYGWIN__) || defined(__CYGWIN32__)
|
||||||
#define GLOG_OS_CYGWIN
|
# define GLOG_OS_CYGWIN
|
||||||
#elif defined(linux) || defined(__linux) || defined(__linux__)
|
#elif defined(linux) || defined(__linux) || defined(__linux__)
|
||||||
#ifndef GLOG_OS_LINUX
|
# ifndef GLOG_OS_LINUX
|
||||||
#define GLOG_OS_LINUX
|
# define GLOG_OS_LINUX
|
||||||
#endif
|
# endif
|
||||||
#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
|
#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
|
||||||
#define GLOG_OS_MACOSX
|
# define GLOG_OS_MACOSX
|
||||||
#elif defined(__FreeBSD__)
|
#elif defined(__FreeBSD__)
|
||||||
#define GLOG_OS_FREEBSD
|
# define GLOG_OS_FREEBSD
|
||||||
#elif defined(__NetBSD__)
|
#elif defined(__NetBSD__)
|
||||||
#define GLOG_OS_NETBSD
|
# define GLOG_OS_NETBSD
|
||||||
#elif defined(__OpenBSD__)
|
#elif defined(__OpenBSD__)
|
||||||
#define GLOG_OS_OPENBSD
|
# define GLOG_OS_OPENBSD
|
||||||
#elif defined(__EMSCRIPTEN__)
|
#elif defined(__EMSCRIPTEN__)
|
||||||
#define GLOG_OS_EMSCRIPTEN
|
# define GLOG_OS_EMSCRIPTEN
|
||||||
#else
|
#else
|
||||||
// TODO(hamaji): Add other platforms.
|
// TODO(hamaji): Add other platforms.
|
||||||
#error Platform not supported by glog. Please consider to contribute platform information by submitting a pull request on Github.
|
#error Platform not supported by glog. Please consider to contribute platform information by submitting a pull request on Github.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // GLOG_PLATFORM_H
|
#endif // GLOG_PLATFORM_H
|
||||||
|
|||||||
@ -44,8 +44,8 @@ namespace google {
|
|||||||
#include "glog/vlog_is_on.h"
|
#include "glog/vlog_is_on.h"
|
||||||
|
|
||||||
#if defined(__GNUC__)
|
#if defined(__GNUC__)
|
||||||
#pragma GCC diagnostic push
|
# pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wvariadic-macros"
|
# pragma GCC diagnostic ignored "-Wvariadic-macros"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// This is similar to LOG(severity) << format... and VLOG(level) << format..,
|
// This is similar to LOG(severity) << format... and VLOG(level) << format..,
|
||||||
@ -85,46 +85,46 @@ namespace google {
|
|||||||
// The following STRIP_LOG testing is performed in the header file so that it's
|
// The following STRIP_LOG testing is performed in the header file so that it's
|
||||||
// possible to completely compile out the logging code and the log messages.
|
// possible to completely compile out the logging code and the log messages.
|
||||||
#if !defined(STRIP_LOG) || STRIP_LOG == 0
|
#if !defined(STRIP_LOG) || STRIP_LOG == 0
|
||||||
#define RAW_VLOG(verboselevel, ...) \
|
# define RAW_VLOG(verboselevel, ...) \
|
||||||
do { \
|
do { \
|
||||||
if (VLOG_IS_ON(verboselevel)) { \
|
if (VLOG_IS_ON(verboselevel)) { \
|
||||||
RAW_LOG_INFO(__VA_ARGS__); \
|
RAW_LOG_INFO(__VA_ARGS__); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
#else
|
#else
|
||||||
#define RAW_VLOG(verboselevel, ...) RawLogStub__(0, __VA_ARGS__)
|
# define RAW_VLOG(verboselevel, ...) RawLogStub__(0, __VA_ARGS__)
|
||||||
#endif // STRIP_LOG == 0
|
#endif // STRIP_LOG == 0
|
||||||
|
|
||||||
#if !defined(STRIP_LOG) || STRIP_LOG == 0
|
#if !defined(STRIP_LOG) || STRIP_LOG == 0
|
||||||
#define RAW_LOG_INFO(...) \
|
# define RAW_LOG_INFO(...) \
|
||||||
google::RawLog__(google::GLOG_INFO, __FILE__, __LINE__, __VA_ARGS__)
|
google::RawLog__(google::GLOG_INFO, __FILE__, __LINE__, __VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#define RAW_LOG_INFO(...) google::RawLogStub__(0, __VA_ARGS__)
|
# define RAW_LOG_INFO(...) google::RawLogStub__(0, __VA_ARGS__)
|
||||||
#endif // STRIP_LOG == 0
|
#endif // STRIP_LOG == 0
|
||||||
|
|
||||||
#if !defined(STRIP_LOG) || STRIP_LOG <= 1
|
#if !defined(STRIP_LOG) || STRIP_LOG <= 1
|
||||||
#define RAW_LOG_WARNING(...) \
|
# define RAW_LOG_WARNING(...) \
|
||||||
google::RawLog__(google::GLOG_WARNING, __FILE__, __LINE__, __VA_ARGS__)
|
google::RawLog__(google::GLOG_WARNING, __FILE__, __LINE__, __VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#define RAW_LOG_WARNING(...) google::RawLogStub__(0, __VA_ARGS__)
|
# define RAW_LOG_WARNING(...) google::RawLogStub__(0, __VA_ARGS__)
|
||||||
#endif // STRIP_LOG <= 1
|
#endif // STRIP_LOG <= 1
|
||||||
|
|
||||||
#if !defined(STRIP_LOG) || STRIP_LOG <= 2
|
#if !defined(STRIP_LOG) || STRIP_LOG <= 2
|
||||||
#define RAW_LOG_ERROR(...) \
|
# define RAW_LOG_ERROR(...) \
|
||||||
google::RawLog__(google::GLOG_ERROR, __FILE__, __LINE__, __VA_ARGS__)
|
google::RawLog__(google::GLOG_ERROR, __FILE__, __LINE__, __VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#define RAW_LOG_ERROR(...) google::RawLogStub__(0, __VA_ARGS__)
|
# define RAW_LOG_ERROR(...) google::RawLogStub__(0, __VA_ARGS__)
|
||||||
#endif // STRIP_LOG <= 2
|
#endif // STRIP_LOG <= 2
|
||||||
|
|
||||||
#if !defined(STRIP_LOG) || STRIP_LOG <= 3
|
#if !defined(STRIP_LOG) || STRIP_LOG <= 3
|
||||||
#define RAW_LOG_FATAL(...) \
|
# define RAW_LOG_FATAL(...) \
|
||||||
google::RawLog__(google::GLOG_FATAL, __FILE__, __LINE__, __VA_ARGS__)
|
google::RawLog__(google::GLOG_FATAL, __FILE__, __LINE__, __VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#define RAW_LOG_FATAL(...) \
|
# define RAW_LOG_FATAL(...) \
|
||||||
do { \
|
do { \
|
||||||
google::RawLogStub__(0, __VA_ARGS__); \
|
google::RawLogStub__(0, __VA_ARGS__); \
|
||||||
exit(EXIT_FAILURE); \
|
exit(EXIT_FAILURE); \
|
||||||
} while (0)
|
} while (0)
|
||||||
#endif // STRIP_LOG <= 3
|
#endif // STRIP_LOG <= 3
|
||||||
|
|
||||||
// Similar to CHECK(condition) << message,
|
// Similar to CHECK(condition) << message,
|
||||||
@ -142,20 +142,20 @@ namespace google {
|
|||||||
// Debug versions of RAW_LOG and RAW_CHECK
|
// Debug versions of RAW_LOG and RAW_CHECK
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
|
||||||
#define RAW_DLOG(severity, ...) RAW_LOG(severity, __VA_ARGS__)
|
# define RAW_DLOG(severity, ...) RAW_LOG(severity, __VA_ARGS__)
|
||||||
#define RAW_DCHECK(condition, message) RAW_CHECK(condition, message)
|
# define RAW_DCHECK(condition, message) RAW_CHECK(condition, message)
|
||||||
|
|
||||||
#else // NDEBUG
|
#else // NDEBUG
|
||||||
|
|
||||||
#define RAW_DLOG(severity, ...) \
|
# define RAW_DLOG(severity, ...) \
|
||||||
while (false) RAW_LOG(severity, __VA_ARGS__)
|
while (false) RAW_LOG(severity, __VA_ARGS__)
|
||||||
#define RAW_DCHECK(condition, message) \
|
# define RAW_DCHECK(condition, message) \
|
||||||
while (false) RAW_CHECK(condition, message)
|
while (false) RAW_CHECK(condition, message)
|
||||||
|
|
||||||
#endif // NDEBUG
|
#endif // NDEBUG
|
||||||
|
|
||||||
#if defined(__GNUC__)
|
#if defined(__GNUC__)
|
||||||
#pragma GCC diagnostic pop
|
# pragma GCC diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Stub log function used to work around for unused variable warnings when
|
// Stub log function used to work around for unused variable warnings when
|
||||||
@ -169,9 +169,9 @@ static inline void RawLogStub__(int /* ignored */, ...) {}
|
|||||||
GLOG_EXPORT void RawLog__(LogSeverity severity, const char* file, int line,
|
GLOG_EXPORT void RawLog__(LogSeverity severity, const char* file, int line,
|
||||||
const char* format, ...)
|
const char* format, ...)
|
||||||
#if defined(__has_attribute)
|
#if defined(__has_attribute)
|
||||||
#if __has_attribute(used)
|
# if __has_attribute(used)
|
||||||
__attribute__((__format__(__printf__, 4, 5)))
|
__attribute__((__format__(__printf__, 4, 5)))
|
||||||
#endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
} // namespace google
|
} // namespace google
|
||||||
|
|||||||
@ -72,20 +72,21 @@
|
|||||||
// it's either FLAGS_v or an appropriate internal variable
|
// it's either FLAGS_v or an appropriate internal variable
|
||||||
// matching the current source file that represents results of
|
// matching the current source file that represents results of
|
||||||
// parsing of --vmodule flag and/or SetVLOGLevel calls.
|
// parsing of --vmodule flag and/or SetVLOGLevel calls.
|
||||||
#define VLOG_IS_ON(verboselevel) \
|
# define VLOG_IS_ON(verboselevel) \
|
||||||
__extension__({ \
|
__extension__({ \
|
||||||
static google::SiteFlag vlocal__ = {nullptr, nullptr, 0, nullptr}; \
|
static google::SiteFlag vlocal__ = {nullptr, nullptr, 0, nullptr}; \
|
||||||
GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized( \
|
GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized( \
|
||||||
__FILE__, __LINE__, &vlocal__, sizeof(google::SiteFlag), "")); \
|
__FILE__, __LINE__, &vlocal__, sizeof(google::SiteFlag), "")); \
|
||||||
google::int32 verbose_level__ = (verboselevel); \
|
google::int32 verbose_level__ = (verboselevel); \
|
||||||
(vlocal__.level == nullptr \
|
(vlocal__.level == nullptr \
|
||||||
? google::InitVLOG3__(&vlocal__, &FLAGS_v, __FILE__, verbose_level__) \
|
? google::InitVLOG3__(&vlocal__, &FLAGS_v, __FILE__, \
|
||||||
: *vlocal__.level >= verbose_level__); \
|
verbose_level__) \
|
||||||
})
|
: *vlocal__.level >= verbose_level__); \
|
||||||
|
})
|
||||||
#else
|
#else
|
||||||
// GNU extensions not available, so we do not support --vmodule.
|
// GNU extensions not available, so we do not support --vmodule.
|
||||||
// Dynamic value of FLAGS_v always controls the logging level.
|
// Dynamic value of FLAGS_v always controls the logging level.
|
||||||
#define VLOG_IS_ON(verboselevel) (FLAGS_v >= (verboselevel))
|
# define VLOG_IS_ON(verboselevel) (FLAGS_v >= (verboselevel))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Set VLOG(_IS_ON) level for module_pattern to log_level.
|
// Set VLOG(_IS_ON) level for module_pattern to log_level.
|
||||||
|
|||||||
238
src/googletest.h
238
src/googletest.h
@ -31,7 +31,7 @@
|
|||||||
// (based on googletest: http://code.google.com/p/googletest/)
|
// (based on googletest: http://code.google.com/p/googletest/)
|
||||||
|
|
||||||
#ifdef GOOGLETEST_H__
|
#ifdef GOOGLETEST_H__
|
||||||
#error You must not include this file twice.
|
# error You must not include this file twice.
|
||||||
#endif
|
#endif
|
||||||
#define GOOGLETEST_H__
|
#define GOOGLETEST_H__
|
||||||
|
|
||||||
@ -53,15 +53,15 @@
|
|||||||
|
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "base/commandlineflags.h"
|
#include "base/commandlineflags.h"
|
||||||
|
|
||||||
#if __cplusplus < 201103L && !defined(_MSC_VER)
|
#if __cplusplus < 201103L && !defined(_MSC_VER)
|
||||||
#define GOOGLE_GLOG_THROW_BAD_ALLOC throw (std::bad_alloc)
|
# define GOOGLE_GLOG_THROW_BAD_ALLOC throw(std::bad_alloc)
|
||||||
#else
|
#else
|
||||||
#define GOOGLE_GLOG_THROW_BAD_ALLOC
|
# define GOOGLE_GLOG_THROW_BAD_ALLOC
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using std::map;
|
using std::map;
|
||||||
@ -95,7 +95,7 @@ static inline string GetTempDir() {
|
|||||||
// (e.g., glog/vsproject/logging_unittest).
|
// (e.g., glog/vsproject/logging_unittest).
|
||||||
static const char TEST_SRC_DIR[] = "../..";
|
static const char TEST_SRC_DIR[] = "../..";
|
||||||
#elif !defined(TEST_SRC_DIR)
|
#elif !defined(TEST_SRC_DIR)
|
||||||
# warning TEST_SRC_DIR should be defined in config.h
|
# warning TEST_SRC_DIR should be defined in config.h
|
||||||
static const char TEST_SRC_DIR[] = ".";
|
static const char TEST_SRC_DIR[] = ".";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -112,10 +112,10 @@ DEFINE_int32(benchmark_iters, 100000, "Number of iterations per benchmark");
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_LIB_GTEST
|
#ifdef HAVE_LIB_GTEST
|
||||||
# include <gtest/gtest.h>
|
# include <gtest/gtest.h>
|
||||||
// Use our ASSERT_DEATH implementation.
|
// Use our ASSERT_DEATH implementation.
|
||||||
# undef ASSERT_DEATH
|
# undef ASSERT_DEATH
|
||||||
# undef ASSERT_DEBUG_DEATH
|
# undef ASSERT_DEBUG_DEATH
|
||||||
using testing::InitGoogleTest;
|
using testing::InitGoogleTest;
|
||||||
#else
|
#else
|
||||||
|
|
||||||
@ -127,81 +127,83 @@ void InitGoogleTest(int*, char**) {}
|
|||||||
|
|
||||||
// The following is some bare-bones testing infrastructure
|
// The following is some bare-bones testing infrastructure
|
||||||
|
|
||||||
#define EXPECT_NEAR(val1, val2, abs_error) \
|
# define EXPECT_NEAR(val1, val2, abs_error) \
|
||||||
do { \
|
do { \
|
||||||
if (abs(val1 - val2) > abs_error) { \
|
if (abs(val1 - val2) > abs_error) { \
|
||||||
fprintf(stderr, "Check failed: %s within %s of %s\n", #val1, #abs_error, \
|
fprintf(stderr, "Check failed: %s within %s of %s\n", #val1, \
|
||||||
#val2); \
|
#abs_error, #val2); \
|
||||||
exit(EXIT_FAILURE); \
|
exit(EXIT_FAILURE); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define EXPECT_TRUE(cond) \
|
# define EXPECT_TRUE(cond) \
|
||||||
do { \
|
do { \
|
||||||
if (!(cond)) { \
|
if (!(cond)) { \
|
||||||
fprintf(stderr, "Check failed: %s\n", #cond); \
|
fprintf(stderr, "Check failed: %s\n", #cond); \
|
||||||
exit(EXIT_FAILURE); \
|
exit(EXIT_FAILURE); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define EXPECT_FALSE(cond) EXPECT_TRUE(!(cond))
|
# define EXPECT_FALSE(cond) EXPECT_TRUE(!(cond))
|
||||||
|
|
||||||
#define EXPECT_OP(op, val1, val2) \
|
# define EXPECT_OP(op, val1, val2) \
|
||||||
do { \
|
do { \
|
||||||
if (!((val1) op (val2))) { \
|
if (!((val1)op(val2))) { \
|
||||||
fprintf(stderr, "Check failed: %s %s %s\n", #val1, #op, #val2); \
|
fprintf(stderr, "Check failed: %s %s %s\n", #val1, #op, #val2); \
|
||||||
exit(EXIT_FAILURE); \
|
exit(EXIT_FAILURE); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define EXPECT_EQ(val1, val2) EXPECT_OP(==, val1, val2)
|
# define EXPECT_EQ(val1, val2) EXPECT_OP(==, val1, val2)
|
||||||
#define EXPECT_NE(val1, val2) EXPECT_OP(!=, val1, val2)
|
# define EXPECT_NE(val1, val2) EXPECT_OP(!=, val1, val2)
|
||||||
#define EXPECT_GT(val1, val2) EXPECT_OP(>, val1, val2)
|
# define EXPECT_GT(val1, val2) EXPECT_OP(>, val1, val2)
|
||||||
#define EXPECT_LT(val1, val2) EXPECT_OP(<, val1, val2)
|
# define EXPECT_LT(val1, val2) EXPECT_OP(<, val1, val2)
|
||||||
|
|
||||||
#define EXPECT_NAN(arg) \
|
# define EXPECT_NAN(arg) \
|
||||||
do { \
|
do { \
|
||||||
if (!isnan(arg)) { \
|
if (!isnan(arg)) { \
|
||||||
fprintf(stderr, "Check failed: isnan(%s)\n", #arg); \
|
fprintf(stderr, "Check failed: isnan(%s)\n", #arg); \
|
||||||
exit(EXIT_FAILURE); \
|
exit(EXIT_FAILURE); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define EXPECT_INF(arg) \
|
# define EXPECT_INF(arg) \
|
||||||
do { \
|
do { \
|
||||||
if (!isinf(arg)) { \
|
if (!isinf(arg)) { \
|
||||||
fprintf(stderr, "Check failed: isinf(%s)\n", #arg); \
|
fprintf(stderr, "Check failed: isinf(%s)\n", #arg); \
|
||||||
exit(EXIT_FAILURE); \
|
exit(EXIT_FAILURE); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define EXPECT_DOUBLE_EQ(val1, val2) \
|
# define EXPECT_DOUBLE_EQ(val1, val2) \
|
||||||
do { \
|
do { \
|
||||||
if (((val1) < (val2) - 0.001 || (val1) > (val2) + 0.001)) { \
|
if (((val1) < (val2)-0.001 || (val1) > (val2) + 0.001)) { \
|
||||||
fprintf(stderr, "Check failed: %s == %s\n", #val1, #val2); \
|
fprintf(stderr, "Check failed: %s == %s\n", #val1, #val2); \
|
||||||
exit(EXIT_FAILURE); \
|
exit(EXIT_FAILURE); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define EXPECT_STREQ(val1, val2) \
|
# define EXPECT_STREQ(val1, val2) \
|
||||||
do { \
|
do { \
|
||||||
if (strcmp((val1), (val2)) != 0) { \
|
if (strcmp((val1), (val2)) != 0) { \
|
||||||
fprintf(stderr, "Check failed: streq(%s, %s)\n", #val1, #val2); \
|
fprintf(stderr, "Check failed: streq(%s, %s)\n", #val1, #val2); \
|
||||||
exit(EXIT_FAILURE); \
|
exit(EXIT_FAILURE); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
vector<void (*)()> g_testlist; // the tests to run
|
vector<void (*)()> g_testlist; // the tests to run
|
||||||
|
|
||||||
#define TEST(a, b) \
|
# define TEST(a, b) \
|
||||||
struct Test_##a##_##b { \
|
struct Test_##a##_##b { \
|
||||||
Test_##a##_##b() { g_testlist.push_back(&Run); } \
|
Test_##a##_##b() { g_testlist.push_back(&Run); } \
|
||||||
static void Run() { FlagSaver fs; RunTest(); } \
|
static void Run() { \
|
||||||
static void RunTest(); \
|
FlagSaver fs; \
|
||||||
}; \
|
RunTest(); \
|
||||||
static Test_##a##_##b g_test_##a##_##b; \
|
} \
|
||||||
void Test_##a##_##b::RunTest()
|
static void RunTest(); \
|
||||||
|
}; \
|
||||||
|
static Test_##a##_##b g_test_##a##_##b; \
|
||||||
|
void Test_##a##_##b::RunTest()
|
||||||
|
|
||||||
static inline int RUN_ALL_TESTS() {
|
static inline int RUN_ALL_TESTS() {
|
||||||
vector<void (*)()>::const_iterator it;
|
vector<void (*)()>::const_iterator it;
|
||||||
@ -228,33 +230,33 @@ static inline void CalledAbort() {
|
|||||||
|
|
||||||
#ifdef GLOG_OS_WINDOWS
|
#ifdef GLOG_OS_WINDOWS
|
||||||
// TODO(hamaji): Death test somehow doesn't work in Windows.
|
// TODO(hamaji): Death test somehow doesn't work in Windows.
|
||||||
#define ASSERT_DEATH(fn, msg)
|
# define ASSERT_DEATH(fn, msg)
|
||||||
#else
|
#else
|
||||||
#define ASSERT_DEATH(fn, msg) \
|
# define ASSERT_DEATH(fn, msg) \
|
||||||
do { \
|
do { \
|
||||||
g_called_abort = false; \
|
g_called_abort = false; \
|
||||||
/* in logging.cc */ \
|
/* in logging.cc */ \
|
||||||
void (*original_logging_fail_func)() = g_logging_fail_func; \
|
void (*original_logging_fail_func)() = g_logging_fail_func; \
|
||||||
g_logging_fail_func = &CalledAbort; \
|
g_logging_fail_func = &CalledAbort; \
|
||||||
if (!setjmp(g_jmp_buf)) fn; \
|
if (!setjmp(g_jmp_buf)) fn; \
|
||||||
/* set back to their default */ \
|
/* set back to their default */ \
|
||||||
g_logging_fail_func = original_logging_fail_func; \
|
g_logging_fail_func = original_logging_fail_func; \
|
||||||
if (!g_called_abort) { \
|
if (!g_called_abort) { \
|
||||||
fprintf(stderr, "Function didn't die (%s): %s\n", msg, #fn); \
|
fprintf(stderr, "Function didn't die (%s): %s\n", msg, #fn); \
|
||||||
exit(EXIT_FAILURE); \
|
exit(EXIT_FAILURE); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
#define ASSERT_DEBUG_DEATH(fn, msg)
|
# define ASSERT_DEBUG_DEATH(fn, msg)
|
||||||
#else
|
#else
|
||||||
#define ASSERT_DEBUG_DEATH(fn, msg) ASSERT_DEATH(fn, msg)
|
# define ASSERT_DEBUG_DEATH(fn, msg) ASSERT_DEATH(fn, msg)
|
||||||
#endif // NDEBUG
|
#endif // NDEBUG
|
||||||
|
|
||||||
// Benchmark tools.
|
// Benchmark tools.
|
||||||
|
|
||||||
#define BENCHMARK(n) static BenchmarkRegisterer __benchmark_ ## n (#n, &n);
|
#define BENCHMARK(n) static BenchmarkRegisterer __benchmark_##n(#n, &n);
|
||||||
|
|
||||||
map<string, void (*)(int)> g_benchlist; // the benchmarks to run
|
map<string, void (*)(int)> g_benchlist; // the benchmarks to run
|
||||||
|
|
||||||
@ -278,13 +280,13 @@ static inline void RunSpecifiedBenchmarks() {
|
|||||||
double elapsed_ns = (static_cast<double>(clock()) - start) /
|
double elapsed_ns = (static_cast<double>(clock()) - start) /
|
||||||
CLOCKS_PER_SEC * 1000 * 1000 * 1000;
|
CLOCKS_PER_SEC * 1000 * 1000 * 1000;
|
||||||
#if defined(__GNUC__) && !defined(__clang__)
|
#if defined(__GNUC__) && !defined(__clang__)
|
||||||
#pragma GCC diagnostic push
|
# pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wformat="
|
# pragma GCC diagnostic ignored "-Wformat="
|
||||||
#endif
|
#endif
|
||||||
printf("%s\t%8.2lf\t%10d\n", iter.first.c_str(), elapsed_ns / iter_cnt,
|
printf("%s\t%8.2lf\t%10d\n", iter.first.c_str(), elapsed_ns / iter_cnt,
|
||||||
iter_cnt);
|
iter_cnt);
|
||||||
#if defined(__GNUC__) && !defined(__clang__)
|
#if defined(__GNUC__) && !defined(__clang__)
|
||||||
#pragma GCC diagnostic pop
|
# pragma GCC diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
puts("");
|
puts("");
|
||||||
@ -317,8 +319,7 @@ class CapturedStream {
|
|||||||
CHECK(uncaptured_fd_ != -1);
|
CHECK(uncaptured_fd_ != -1);
|
||||||
|
|
||||||
// Open file to save stream to
|
// Open file to save stream to
|
||||||
int cap_fd = open(filename_.c_str(),
|
int cap_fd = open(filename_.c_str(), O_CREAT | O_TRUNC | O_WRONLY,
|
||||||
O_CREAT | O_TRUNC | O_WRONLY,
|
|
||||||
S_IRUSR | S_IWUSR);
|
S_IRUSR | S_IWUSR);
|
||||||
CHECK(cap_fd != -1);
|
CHECK(cap_fd != -1);
|
||||||
|
|
||||||
@ -337,18 +338,18 @@ class CapturedStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const string & filename() const { return filename_; }
|
const string& filename() const { return filename_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int fd_; // file descriptor being captured
|
int fd_; // file descriptor being captured
|
||||||
int uncaptured_fd_{-1}; // where the stream was originally being sent to
|
int uncaptured_fd_{-1}; // where the stream was originally being sent to
|
||||||
string filename_; // file where stream is being saved
|
string filename_; // file where stream is being saved
|
||||||
};
|
};
|
||||||
static CapturedStream * s_captured_streams[STDERR_FILENO+1];
|
static CapturedStream* s_captured_streams[STDERR_FILENO + 1];
|
||||||
// Redirect a file descriptor to a file.
|
// Redirect a file descriptor to a file.
|
||||||
// fd - Should be STDOUT_FILENO or STDERR_FILENO
|
// fd - Should be STDOUT_FILENO or STDERR_FILENO
|
||||||
// filename - File where output should be stored
|
// filename - File where output should be stored
|
||||||
static inline void CaptureTestOutput(int fd, const string & filename) {
|
static inline void CaptureTestOutput(int fd, const string& filename) {
|
||||||
CHECK((fd == STDOUT_FILENO) || (fd == STDERR_FILENO));
|
CHECK((fd == STDOUT_FILENO) || (fd == STDERR_FILENO));
|
||||||
CHECK(s_captured_streams[fd] == nullptr);
|
CHECK(s_captured_streams[fd] == nullptr);
|
||||||
s_captured_streams[fd] = new CapturedStream(fd, filename);
|
s_captured_streams[fd] = new CapturedStream(fd, filename);
|
||||||
@ -360,14 +361,14 @@ static inline void CaptureTestStderr() {
|
|||||||
CaptureTestOutput(STDERR_FILENO, FLAGS_test_tmpdir + "/captured.err");
|
CaptureTestOutput(STDERR_FILENO, FLAGS_test_tmpdir + "/captured.err");
|
||||||
}
|
}
|
||||||
// Return the size (in bytes) of a file
|
// Return the size (in bytes) of a file
|
||||||
static inline size_t GetFileSize(FILE * file) {
|
static inline size_t GetFileSize(FILE* file) {
|
||||||
fseek(file, 0, SEEK_END);
|
fseek(file, 0, SEEK_END);
|
||||||
return static_cast<size_t>(ftell(file));
|
return static_cast<size_t>(ftell(file));
|
||||||
}
|
}
|
||||||
// Read the entire content of a file as a string
|
// Read the entire content of a file as a string
|
||||||
static inline string ReadEntireFile(FILE * file) {
|
static inline string ReadEntireFile(FILE* file) {
|
||||||
const size_t file_size = GetFileSize(file);
|
const size_t file_size = GetFileSize(file);
|
||||||
char * const buffer = new char[file_size];
|
char* const buffer = new char[file_size];
|
||||||
|
|
||||||
size_t bytes_last_read = 0; // # of bytes read in the last fread()
|
size_t bytes_last_read = 0; // # of bytes read in the last fread()
|
||||||
size_t bytes_read = 0; // # of bytes read so far
|
size_t bytes_read = 0; // # of bytes read so far
|
||||||
@ -377,11 +378,12 @@ static inline string ReadEntireFile(FILE * file) {
|
|||||||
// Keep reading the file until we cannot read further or the
|
// Keep reading the file until we cannot read further or the
|
||||||
// pre-determined file size is reached.
|
// pre-determined file size is reached.
|
||||||
do {
|
do {
|
||||||
bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file);
|
bytes_last_read =
|
||||||
|
fread(buffer + bytes_read, 1, file_size - bytes_read, file);
|
||||||
bytes_read += bytes_last_read;
|
bytes_read += bytes_last_read;
|
||||||
} while (bytes_last_read > 0 && bytes_read < file_size);
|
} while (bytes_last_read > 0 && bytes_read < file_size);
|
||||||
|
|
||||||
const string content = string(buffer, buffer+bytes_read);
|
const string content = string(buffer, buffer + bytes_read);
|
||||||
delete[] buffer;
|
delete[] buffer;
|
||||||
|
|
||||||
return content;
|
return content;
|
||||||
@ -390,15 +392,14 @@ static inline string ReadEntireFile(FILE * file) {
|
|||||||
// fd is STDERR_FILENO) as a string
|
// fd is STDERR_FILENO) as a string
|
||||||
static inline string GetCapturedTestOutput(int fd) {
|
static inline string GetCapturedTestOutput(int fd) {
|
||||||
CHECK(fd == STDOUT_FILENO || fd == STDERR_FILENO);
|
CHECK(fd == STDOUT_FILENO || fd == STDERR_FILENO);
|
||||||
CapturedStream * const cap = s_captured_streams[fd];
|
CapturedStream* const cap = s_captured_streams[fd];
|
||||||
CHECK(cap)
|
CHECK(cap) << ": did you forget CaptureTestStdout() or CaptureTestStderr()?";
|
||||||
<< ": did you forget CaptureTestStdout() or CaptureTestStderr()?";
|
|
||||||
|
|
||||||
// Make sure everything is flushed.
|
// Make sure everything is flushed.
|
||||||
cap->StopCapture();
|
cap->StopCapture();
|
||||||
|
|
||||||
// Read the captured file.
|
// Read the captured file.
|
||||||
FILE * const file = fopen(cap->filename().c_str(), "r");
|
FILE* const file = fopen(cap->filename().c_str(), "r");
|
||||||
const string content = ReadEntireFile(file);
|
const string content = ReadEntireFile(file);
|
||||||
fclose(file);
|
fclose(file);
|
||||||
|
|
||||||
@ -421,7 +422,7 @@ static inline bool IsLoggingPrefix(const string& s) {
|
|||||||
}
|
}
|
||||||
if (!strchr("IWEF", s[0])) return false;
|
if (!strchr("IWEF", s[0])) return false;
|
||||||
for (size_t i = 1; i <= 8; ++i) {
|
for (size_t i = 1; i <= 8; ++i) {
|
||||||
if (!isdigit(s[i]) && s[i] != "YEARDATE"[i-1]) return false;
|
if (!isdigit(s[i]) && s[i] != "YEARDATE"[i - 1]) return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -461,16 +462,15 @@ static inline string MungeLine(const string& line) {
|
|||||||
}
|
}
|
||||||
size_t index = thread_lineinfo.find(':');
|
size_t index = thread_lineinfo.find(':');
|
||||||
CHECK_NE(string::npos, index);
|
CHECK_NE(string::npos, index);
|
||||||
thread_lineinfo = thread_lineinfo.substr(0, index+1) + "LINE]";
|
thread_lineinfo = thread_lineinfo.substr(0, index + 1) + "LINE]";
|
||||||
string rest;
|
string rest;
|
||||||
std::getline(iss, rest);
|
std::getline(iss, rest);
|
||||||
return (before + logcode_date[0] + "YEARDATE TIME__ " + thread_lineinfo +
|
return (before + logcode_date[0] + "YEARDATE TIME__ " + thread_lineinfo +
|
||||||
MungeLine(rest));
|
MungeLine(rest));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void StringReplace(string* str,
|
static inline void StringReplace(string* str, const string& oldsub,
|
||||||
const string& oldsub,
|
const string& newsub) {
|
||||||
const string& newsub) {
|
|
||||||
size_t pos = str->find(oldsub);
|
size_t pos = str->find(oldsub);
|
||||||
if (pos != string::npos) {
|
if (pos != string::npos) {
|
||||||
str->replace(pos, oldsub.size(), newsub);
|
str->replace(pos, oldsub.size(), newsub);
|
||||||
@ -589,9 +589,7 @@ class Thread {
|
|||||||
handle_ = CreateThread(nullptr, 0, &Thread::InvokeThreadW, this, 0, &th_);
|
handle_ = CreateThread(nullptr, 0, &Thread::InvokeThreadW, this, 0, &th_);
|
||||||
CHECK(handle_) << "CreateThread";
|
CHECK(handle_) << "CreateThread";
|
||||||
}
|
}
|
||||||
void Join() {
|
void Join() { WaitForSingleObject(handle_, INFINITE); }
|
||||||
WaitForSingleObject(handle_, INFINITE);
|
|
||||||
}
|
|
||||||
#elif defined(HAVE_PTHREAD)
|
#elif defined(HAVE_PTHREAD)
|
||||||
void Start() { pthread_create(&th_, nullptr, &Thread::InvokeThread, this); }
|
void Start() { pthread_create(&th_, nullptr, &Thread::InvokeThread, this); }
|
||||||
void Join() { pthread_join(th_, nullptr); }
|
void Join() { pthread_join(th_, nullptr); }
|
||||||
@ -623,12 +621,12 @@ class Thread {
|
|||||||
|
|
||||||
static inline void SleepForMilliseconds(unsigned t) {
|
static inline void SleepForMilliseconds(unsigned t) {
|
||||||
#ifndef GLOG_OS_WINDOWS
|
#ifndef GLOG_OS_WINDOWS
|
||||||
# if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L
|
# if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L
|
||||||
const struct timespec req = {0, t * 1000 * 1000};
|
const struct timespec req = {0, t * 1000 * 1000};
|
||||||
nanosleep(&req, nullptr);
|
nanosleep(&req, nullptr);
|
||||||
# else
|
# else
|
||||||
usleep(t * 1000);
|
usleep(t * 1000);
|
||||||
# endif
|
# endif
|
||||||
#else
|
#else
|
||||||
Sleep(t);
|
Sleep(t);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
786
src/logging.cc
786
src/logging.cc
File diff suppressed because it is too large
Load Diff
@ -29,19 +29,19 @@
|
|||||||
//
|
//
|
||||||
// Author: Ray Sidney
|
// Author: Ray Sidney
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
|
||||||
#include <fcntl.h>
|
|
||||||
#ifdef HAVE_GLOB_H
|
#ifdef HAVE_GLOB_H
|
||||||
# include <glob.h>
|
# include <glob.h>
|
||||||
#endif
|
#endif
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_SYS_WAIT_H
|
#ifdef HAVE_SYS_WAIT_H
|
||||||
# include <sys/wait.h>
|
# include <sys/wait.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
@ -63,13 +63,14 @@
|
|||||||
DECLARE_string(log_backtrace_at); // logging.cc
|
DECLARE_string(log_backtrace_at); // logging.cc
|
||||||
|
|
||||||
#ifdef GLOG_USE_GFLAGS
|
#ifdef GLOG_USE_GFLAGS
|
||||||
#include <gflags/gflags.h>
|
# include <gflags/gflags.h>
|
||||||
using namespace GFLAGS_NAMESPACE;
|
using namespace GFLAGS_NAMESPACE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_LIB_GMOCK
|
#ifdef HAVE_LIB_GMOCK
|
||||||
#include <gmock/gmock.h>
|
# include <gmock/gmock.h>
|
||||||
#include "mock-log.h"
|
|
||||||
|
# include "mock-log.h"
|
||||||
// Introduce several symbols from gmock.
|
// Introduce several symbols from gmock.
|
||||||
using google::glog_testing::ScopedMockLog;
|
using google::glog_testing::ScopedMockLog;
|
||||||
using testing::_;
|
using testing::_;
|
||||||
@ -132,7 +133,8 @@ static void BM_Check1(int n) {
|
|||||||
}
|
}
|
||||||
BENCHMARK(BM_Check1)
|
BENCHMARK(BM_Check1)
|
||||||
|
|
||||||
static void CheckFailure(int a, int b, const char* file, int line, const char* msg);
|
static void CheckFailure(int a, int b, const char* file, int line,
|
||||||
|
const char* msg);
|
||||||
static void BM_Check3(int n) {
|
static void BM_Check3(int n) {
|
||||||
while (n-- > 0) {
|
while (n-- > 0) {
|
||||||
if (n < x) CheckFailure(n, x, __FILE__, __LINE__, "n < x");
|
if (n < x) CheckFailure(n, x, __FILE__, __LINE__, "n < x");
|
||||||
@ -165,8 +167,7 @@ static void BM_Check2(int n) {
|
|||||||
BENCHMARK(BM_Check2)
|
BENCHMARK(BM_Check2)
|
||||||
|
|
||||||
static void CheckFailure(int, int, const char* /* file */, int /* line */,
|
static void CheckFailure(int, int, const char* /* file */, int /* line */,
|
||||||
const char* /* msg */) {
|
const char* /* msg */) {}
|
||||||
}
|
|
||||||
|
|
||||||
static void BM_logspeed(int n) {
|
static void BM_logspeed(int n) {
|
||||||
while (n-- > 0) {
|
while (n-- > 0) {
|
||||||
@ -182,31 +183,24 @@ static void BM_vlog(int n) {
|
|||||||
}
|
}
|
||||||
BENCHMARK(BM_vlog)
|
BENCHMARK(BM_vlog)
|
||||||
|
|
||||||
// Dynamically generate a prefix using the default format and write it to the stream.
|
// Dynamically generate a prefix using the default format and write it to the
|
||||||
void PrefixAttacher(std::ostream &s, const LogMessageInfo &l, void* data) {
|
// stream.
|
||||||
|
void PrefixAttacher(std::ostream& s, const LogMessageInfo& l, void* data) {
|
||||||
// Assert that `data` contains the expected contents before producing the
|
// Assert that `data` contains the expected contents before producing the
|
||||||
// prefix (otherwise causing the tests to fail):
|
// prefix (otherwise causing the tests to fail):
|
||||||
if (data == nullptr || *static_cast<string*>(data) != "good data") {
|
if (data == nullptr || *static_cast<string*>(data) != "good data") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
s << l.severity[0]
|
s << l.severity[0] << setw(4) << 1900 + l.time.year() << setw(2)
|
||||||
<< setw(4) << 1900 + l.time.year()
|
<< 1 + l.time.month() << setw(2) << l.time.day() << ' ' << setw(2)
|
||||||
<< setw(2) << 1 + l.time.month()
|
<< l.time.hour() << ':' << setw(2) << l.time.min() << ':' << setw(2)
|
||||||
<< setw(2) << l.time.day()
|
<< l.time.sec() << "." << setw(6) << l.time.usec() << ' ' << setfill(' ')
|
||||||
<< ' '
|
<< setw(5) << l.thread_id << setfill('0') << ' ' << l.filename << ':'
|
||||||
<< setw(2) << l.time.hour() << ':'
|
<< l.line_number << "]";
|
||||||
<< setw(2) << l.time.min() << ':'
|
|
||||||
<< setw(2) << l.time.sec() << "."
|
|
||||||
<< setw(6) << l.time.usec()
|
|
||||||
<< ' '
|
|
||||||
<< setfill(' ') << setw(5)
|
|
||||||
<< l.thread_id << setfill('0')
|
|
||||||
<< ' '
|
|
||||||
<< l.filename << ':' << l.line_number << "]";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char** argv) {
|
||||||
FLAGS_colorlogtostderr = false;
|
FLAGS_colorlogtostderr = false;
|
||||||
FLAGS_timestamp_in_logfile_name = true;
|
FLAGS_timestamp_in_logfile_name = true;
|
||||||
|
|
||||||
@ -216,8 +210,8 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
// Test some basics before InitGoogleLogging:
|
// Test some basics before InitGoogleLogging:
|
||||||
CaptureTestStderr();
|
CaptureTestStderr();
|
||||||
LogWithLevels(FLAGS_v, FLAGS_stderrthreshold,
|
LogWithLevels(FLAGS_v, FLAGS_stderrthreshold, FLAGS_logtostderr,
|
||||||
FLAGS_logtostderr, FLAGS_alsologtostderr);
|
FLAGS_alsologtostderr);
|
||||||
LogWithLevels(0, 0, false, false); // simulate "before global c-tors"
|
LogWithLevels(0, 0, false, false); // simulate "before global c-tors"
|
||||||
const string early_stderr = GetCapturedTestStderr();
|
const string early_stderr = GetCapturedTestStderr();
|
||||||
|
|
||||||
@ -226,7 +220,8 @@ int main(int argc, char **argv) {
|
|||||||
// Setting a custom prefix generator (it will use the default format so that
|
// Setting a custom prefix generator (it will use the default format so that
|
||||||
// the golden outputs can be reused):
|
// the golden outputs can be reused):
|
||||||
string prefix_attacher_data = "good data";
|
string prefix_attacher_data = "good data";
|
||||||
InitGoogleLogging(argv[0], &PrefixAttacher, static_cast<void*>(&prefix_attacher_data));
|
InitGoogleLogging(argv[0], &PrefixAttacher,
|
||||||
|
static_cast<void*>(&prefix_attacher_data));
|
||||||
|
|
||||||
EXPECT_TRUE(IsGoogleLoggingInitialized());
|
EXPECT_TRUE(IsGoogleLoggingInitialized());
|
||||||
|
|
||||||
@ -249,7 +244,8 @@ int main(int argc, char **argv) {
|
|||||||
CaptureTestStderr();
|
CaptureTestStderr();
|
||||||
|
|
||||||
// re-emit early_stderr
|
// re-emit early_stderr
|
||||||
LogMessage("dummy", LogMessage::kNoLogPrefix, GLOG_INFO).stream() << early_stderr;
|
LogMessage("dummy", LogMessage::kNoLogPrefix, GLOG_INFO).stream()
|
||||||
|
<< early_stderr;
|
||||||
|
|
||||||
TestLogging(true);
|
TestLogging(true);
|
||||||
TestRawLogging();
|
TestRawLogging();
|
||||||
@ -301,12 +297,12 @@ int main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TestLogging(bool check_counts) {
|
void TestLogging(bool check_counts) {
|
||||||
int64 base_num_infos = LogMessage::num_messages(GLOG_INFO);
|
int64 base_num_infos = LogMessage::num_messages(GLOG_INFO);
|
||||||
int64 base_num_warning = LogMessage::num_messages(GLOG_WARNING);
|
int64 base_num_warning = LogMessage::num_messages(GLOG_WARNING);
|
||||||
int64 base_num_errors = LogMessage::num_messages(GLOG_ERROR);
|
int64 base_num_errors = LogMessage::num_messages(GLOG_ERROR);
|
||||||
|
|
||||||
LOG(INFO) << string("foo ") << "bar " << 10 << ' ' << 3.4;
|
LOG(INFO) << string("foo ") << "bar " << 10 << ' ' << 3.4;
|
||||||
for ( int i = 0; i < 10; ++i ) {
|
for (int i = 0; i < 10; ++i) {
|
||||||
int old_errno = errno;
|
int old_errno = errno;
|
||||||
errno = i;
|
errno = i;
|
||||||
PLOG_EVERY_N(ERROR, 2) << "Plog every 2, iteration " << COUNTER;
|
PLOG_EVERY_N(ERROR, 2) << "Plog every 2, iteration " << COUNTER;
|
||||||
@ -330,7 +326,7 @@ void TestLogging(bool check_counts) {
|
|||||||
const char const_s[] = "const array";
|
const char const_s[] = "const array";
|
||||||
LOG(INFO) << const_s;
|
LOG(INFO) << const_s;
|
||||||
int j = 1000;
|
int j = 1000;
|
||||||
LOG(ERROR) << string("foo") << ' '<< j << ' ' << setw(10) << j << " "
|
LOG(ERROR) << string("foo") << ' ' << j << ' ' << setw(10) << j << " "
|
||||||
<< setw(1) << hex << j;
|
<< setw(1) << hex << j;
|
||||||
LOG(INFO) << "foo " << std::setw(10) << 1.0;
|
LOG(INFO) << "foo " << std::setw(10) << 1.0;
|
||||||
|
|
||||||
@ -341,32 +337,27 @@ void TestLogging(bool check_counts) {
|
|||||||
LOG(ERROR) << "inner";
|
LOG(ERROR) << "inner";
|
||||||
}
|
}
|
||||||
|
|
||||||
LogMessage("foo", LogMessage::kNoLogPrefix, GLOG_INFO).stream() << "no prefix";
|
LogMessage("foo", LogMessage::kNoLogPrefix, GLOG_INFO).stream()
|
||||||
|
<< "no prefix";
|
||||||
|
|
||||||
if (check_counts) {
|
if (check_counts) {
|
||||||
CHECK_EQ(base_num_infos + 15, LogMessage::num_messages(GLOG_INFO));
|
CHECK_EQ(base_num_infos + 15, LogMessage::num_messages(GLOG_INFO));
|
||||||
CHECK_EQ(base_num_warning + 3, LogMessage::num_messages(GLOG_WARNING));
|
CHECK_EQ(base_num_warning + 3, LogMessage::num_messages(GLOG_WARNING));
|
||||||
CHECK_EQ(base_num_errors + 17, LogMessage::num_messages(GLOG_ERROR));
|
CHECK_EQ(base_num_errors + 17, LogMessage::num_messages(GLOG_ERROR));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void NoAllocNewHook() {
|
static void NoAllocNewHook() { LOG(FATAL) << "unexpected new"; }
|
||||||
LOG(FATAL) << "unexpected new";
|
|
||||||
}
|
|
||||||
|
|
||||||
struct NewHook {
|
struct NewHook {
|
||||||
NewHook() {
|
NewHook() { g_new_hook = &NoAllocNewHook; }
|
||||||
g_new_hook = &NoAllocNewHook;
|
|
||||||
}
|
|
||||||
~NewHook() { g_new_hook = nullptr; }
|
~NewHook() { g_new_hook = nullptr; }
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST(DeathNoAllocNewHook, logging) {
|
TEST(DeathNoAllocNewHook, logging) {
|
||||||
// tests that NewHook used below works
|
// tests that NewHook used below works
|
||||||
NewHook new_hook;
|
NewHook new_hook;
|
||||||
ASSERT_DEATH({
|
ASSERT_DEATH({ new int; }, "unexpected new");
|
||||||
new int;
|
|
||||||
}, "unexpected new");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestRawLogging() {
|
void TestRawLogging() {
|
||||||
@ -425,8 +416,8 @@ void TestRawLogging() {
|
|||||||
|
|
||||||
void LogWithLevels(int v, int severity, bool err, bool alsoerr) {
|
void LogWithLevels(int v, int severity, bool err, bool alsoerr) {
|
||||||
RAW_LOG(INFO,
|
RAW_LOG(INFO,
|
||||||
"Test: v=%d stderrthreshold=%d logtostderr=%d alsologtostderr=%d",
|
"Test: v=%d stderrthreshold=%d logtostderr=%d alsologtostderr=%d", v,
|
||||||
v, severity, err, alsoerr);
|
severity, err, alsoerr);
|
||||||
|
|
||||||
FlagSaver saver;
|
FlagSaver saver;
|
||||||
|
|
||||||
@ -463,28 +454,48 @@ void LogWithLevels(int v, int severity, bool err, bool alsoerr) {
|
|||||||
LOG_IF(ERROR, false) << "don't log_if error";
|
LOG_IF(ERROR, false) << "don't log_if error";
|
||||||
|
|
||||||
int c;
|
int c;
|
||||||
c = 1; VLOG_IF(100, c -= 2) << "vlog_if 100 expr"; EXPECT_EQ(c, -1);
|
c = 1;
|
||||||
c = 1; VLOG_IF(0, c -= 2) << "vlog_if 0 expr"; EXPECT_EQ(c, -1);
|
VLOG_IF(100, c -= 2) << "vlog_if 100 expr";
|
||||||
c = 1; LOG_IF(INFO, c -= 2) << "log_if info expr"; EXPECT_EQ(c, -1);
|
EXPECT_EQ(c, -1);
|
||||||
c = 1; LOG_IF(ERROR, c -= 2) << "log_if error expr"; EXPECT_EQ(c, -1);
|
c = 1;
|
||||||
c = 2; VLOG_IF(0, c -= 2) << "don't vlog_if 0 expr"; EXPECT_EQ(c, 0);
|
VLOG_IF(0, c -= 2) << "vlog_if 0 expr";
|
||||||
c = 2; LOG_IF(ERROR, c -= 2) << "don't log_if error expr"; EXPECT_EQ(c, 0);
|
EXPECT_EQ(c, -1);
|
||||||
|
c = 1;
|
||||||
|
LOG_IF(INFO, c -= 2) << "log_if info expr";
|
||||||
|
EXPECT_EQ(c, -1);
|
||||||
|
c = 1;
|
||||||
|
LOG_IF(ERROR, c -= 2) << "log_if error expr";
|
||||||
|
EXPECT_EQ(c, -1);
|
||||||
|
c = 2;
|
||||||
|
VLOG_IF(0, c -= 2) << "don't vlog_if 0 expr";
|
||||||
|
EXPECT_EQ(c, 0);
|
||||||
|
c = 2;
|
||||||
|
LOG_IF(ERROR, c -= 2) << "don't log_if error expr";
|
||||||
|
EXPECT_EQ(c, 0);
|
||||||
|
|
||||||
c = 3; LOG_IF_EVERY_N(INFO, c -= 4, 1) << "log_if info every 1 expr";
|
c = 3;
|
||||||
|
LOG_IF_EVERY_N(INFO, c -= 4, 1) << "log_if info every 1 expr";
|
||||||
EXPECT_EQ(c, -1);
|
EXPECT_EQ(c, -1);
|
||||||
c = 3; LOG_IF_EVERY_N(ERROR, c -= 4, 1) << "log_if error every 1 expr";
|
c = 3;
|
||||||
|
LOG_IF_EVERY_N(ERROR, c -= 4, 1) << "log_if error every 1 expr";
|
||||||
EXPECT_EQ(c, -1);
|
EXPECT_EQ(c, -1);
|
||||||
c = 4; LOG_IF_EVERY_N(ERROR, c -= 4, 3) << "don't log_if info every 3 expr";
|
c = 4;
|
||||||
|
LOG_IF_EVERY_N(ERROR, c -= 4, 3) << "don't log_if info every 3 expr";
|
||||||
EXPECT_EQ(c, 0);
|
EXPECT_EQ(c, 0);
|
||||||
c = 4; LOG_IF_EVERY_N(ERROR, c -= 4, 3) << "don't log_if error every 3 expr";
|
c = 4;
|
||||||
|
LOG_IF_EVERY_N(ERROR, c -= 4, 3) << "don't log_if error every 3 expr";
|
||||||
EXPECT_EQ(c, 0);
|
EXPECT_EQ(c, 0);
|
||||||
c = 5; VLOG_IF_EVERY_N(0, c -= 4, 1) << "vlog_if 0 every 1 expr";
|
c = 5;
|
||||||
|
VLOG_IF_EVERY_N(0, c -= 4, 1) << "vlog_if 0 every 1 expr";
|
||||||
EXPECT_EQ(c, 1);
|
EXPECT_EQ(c, 1);
|
||||||
c = 5; VLOG_IF_EVERY_N(100, c -= 4, 3) << "vlog_if 100 every 3 expr";
|
c = 5;
|
||||||
|
VLOG_IF_EVERY_N(100, c -= 4, 3) << "vlog_if 100 every 3 expr";
|
||||||
EXPECT_EQ(c, 1);
|
EXPECT_EQ(c, 1);
|
||||||
c = 6; VLOG_IF_EVERY_N(0, c -= 6, 1) << "don't vlog_if 0 every 1 expr";
|
c = 6;
|
||||||
|
VLOG_IF_EVERY_N(0, c -= 6, 1) << "don't vlog_if 0 every 1 expr";
|
||||||
EXPECT_EQ(c, 0);
|
EXPECT_EQ(c, 0);
|
||||||
c = 6; VLOG_IF_EVERY_N(100, c -= 6, 3) << "don't vlog_if 100 every 1 expr";
|
c = 6;
|
||||||
|
VLOG_IF_EVERY_N(100, c -= 6, 3) << "don't vlog_if 100 every 1 expr";
|
||||||
EXPECT_EQ(c, 0);
|
EXPECT_EQ(c, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -523,19 +534,24 @@ TEST(DeathRawCHECK, logging) {
|
|||||||
ASSERT_DEATH(RAW_CHECK(false, "failure 1"),
|
ASSERT_DEATH(RAW_CHECK(false, "failure 1"),
|
||||||
"RAW: Check false failed: failure 1");
|
"RAW: Check false failed: failure 1");
|
||||||
ASSERT_DEBUG_DEATH(RAW_DCHECK(1 == 2, "failure 2"),
|
ASSERT_DEBUG_DEATH(RAW_DCHECK(1 == 2, "failure 2"),
|
||||||
"RAW: Check 1 == 2 failed: failure 2");
|
"RAW: Check 1 == 2 failed: failure 2");
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestLogString() {
|
void TestLogString() {
|
||||||
vector<string> errors;
|
vector<string> errors;
|
||||||
vector<string>* no_errors = nullptr;
|
vector<string>* no_errors = nullptr;
|
||||||
|
|
||||||
LOG_STRING(INFO, &errors) << "LOG_STRING: " << "collected info";
|
LOG_STRING(INFO, &errors) << "LOG_STRING: "
|
||||||
LOG_STRING(WARNING, &errors) << "LOG_STRING: " << "collected warning";
|
<< "collected info";
|
||||||
LOG_STRING(ERROR, &errors) << "LOG_STRING: " << "collected error";
|
LOG_STRING(WARNING, &errors) << "LOG_STRING: "
|
||||||
|
<< "collected warning";
|
||||||
|
LOG_STRING(ERROR, &errors) << "LOG_STRING: "
|
||||||
|
<< "collected error";
|
||||||
|
|
||||||
LOG_STRING(INFO, no_errors) << "LOG_STRING: " << "reported info";
|
LOG_STRING(INFO, no_errors) << "LOG_STRING: "
|
||||||
LOG_STRING(WARNING, no_errors) << "LOG_STRING: " << "reported warning";
|
<< "reported info";
|
||||||
|
LOG_STRING(WARNING, no_errors) << "LOG_STRING: "
|
||||||
|
<< "reported warning";
|
||||||
LOG_STRING(ERROR, nullptr) << "LOG_STRING: "
|
LOG_STRING(ERROR, nullptr) << "LOG_STRING: "
|
||||||
<< "reported error";
|
<< "reported error";
|
||||||
|
|
||||||
@ -548,15 +564,20 @@ void TestLogToString() {
|
|||||||
string error;
|
string error;
|
||||||
string* no_error = nullptr;
|
string* no_error = nullptr;
|
||||||
|
|
||||||
LOG_TO_STRING(INFO, &error) << "LOG_TO_STRING: " << "collected info";
|
LOG_TO_STRING(INFO, &error) << "LOG_TO_STRING: "
|
||||||
|
<< "collected info";
|
||||||
LOG(INFO) << "Captured by LOG_TO_STRING: " << error;
|
LOG(INFO) << "Captured by LOG_TO_STRING: " << error;
|
||||||
LOG_TO_STRING(WARNING, &error) << "LOG_TO_STRING: " << "collected warning";
|
LOG_TO_STRING(WARNING, &error) << "LOG_TO_STRING: "
|
||||||
|
<< "collected warning";
|
||||||
LOG(INFO) << "Captured by LOG_TO_STRING: " << error;
|
LOG(INFO) << "Captured by LOG_TO_STRING: " << error;
|
||||||
LOG_TO_STRING(ERROR, &error) << "LOG_TO_STRING: " << "collected error";
|
LOG_TO_STRING(ERROR, &error) << "LOG_TO_STRING: "
|
||||||
|
<< "collected error";
|
||||||
LOG(INFO) << "Captured by LOG_TO_STRING: " << error;
|
LOG(INFO) << "Captured by LOG_TO_STRING: " << error;
|
||||||
|
|
||||||
LOG_TO_STRING(INFO, no_error) << "LOG_TO_STRING: " << "reported info";
|
LOG_TO_STRING(INFO, no_error) << "LOG_TO_STRING: "
|
||||||
LOG_TO_STRING(WARNING, no_error) << "LOG_TO_STRING: " << "reported warning";
|
<< "reported info";
|
||||||
|
LOG_TO_STRING(WARNING, no_error) << "LOG_TO_STRING: "
|
||||||
|
<< "reported warning";
|
||||||
LOG_TO_STRING(ERROR, nullptr) << "LOG_TO_STRING: "
|
LOG_TO_STRING(ERROR, nullptr) << "LOG_TO_STRING: "
|
||||||
<< "reported error";
|
<< "reported error";
|
||||||
}
|
}
|
||||||
@ -568,8 +589,8 @@ class TestLogSinkImpl : public LogSink {
|
|||||||
const char* base_filename, int line,
|
const char* base_filename, int line,
|
||||||
const LogMessageTime& logmsgtime, const char* message,
|
const LogMessageTime& logmsgtime, const char* message,
|
||||||
size_t message_len) override {
|
size_t message_len) override {
|
||||||
errors.push_back(
|
errors.push_back(ToString(severity, base_filename, line, logmsgtime,
|
||||||
ToString(severity, base_filename, line, logmsgtime, message, message_len));
|
message, message_len));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -577,26 +598,36 @@ void TestLogSink() {
|
|||||||
TestLogSinkImpl sink;
|
TestLogSinkImpl sink;
|
||||||
LogSink* no_sink = nullptr;
|
LogSink* no_sink = nullptr;
|
||||||
|
|
||||||
LOG_TO_SINK(&sink, INFO) << "LOG_TO_SINK: " << "collected info";
|
LOG_TO_SINK(&sink, INFO) << "LOG_TO_SINK: "
|
||||||
LOG_TO_SINK(&sink, WARNING) << "LOG_TO_SINK: " << "collected warning";
|
<< "collected info";
|
||||||
LOG_TO_SINK(&sink, ERROR) << "LOG_TO_SINK: " << "collected error";
|
LOG_TO_SINK(&sink, WARNING) << "LOG_TO_SINK: "
|
||||||
|
<< "collected warning";
|
||||||
|
LOG_TO_SINK(&sink, ERROR) << "LOG_TO_SINK: "
|
||||||
|
<< "collected error";
|
||||||
|
|
||||||
LOG_TO_SINK(no_sink, INFO) << "LOG_TO_SINK: " << "reported info";
|
LOG_TO_SINK(no_sink, INFO) << "LOG_TO_SINK: "
|
||||||
LOG_TO_SINK(no_sink, WARNING) << "LOG_TO_SINK: " << "reported warning";
|
<< "reported info";
|
||||||
|
LOG_TO_SINK(no_sink, WARNING) << "LOG_TO_SINK: "
|
||||||
|
<< "reported warning";
|
||||||
LOG_TO_SINK(nullptr, ERROR) << "LOG_TO_SINK: "
|
LOG_TO_SINK(nullptr, ERROR) << "LOG_TO_SINK: "
|
||||||
<< "reported error";
|
<< "reported error";
|
||||||
|
|
||||||
LOG_TO_SINK_BUT_NOT_TO_LOGFILE(&sink, INFO)
|
LOG_TO_SINK_BUT_NOT_TO_LOGFILE(&sink, INFO)
|
||||||
<< "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: " << "collected info";
|
<< "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: "
|
||||||
|
<< "collected info";
|
||||||
LOG_TO_SINK_BUT_NOT_TO_LOGFILE(&sink, WARNING)
|
LOG_TO_SINK_BUT_NOT_TO_LOGFILE(&sink, WARNING)
|
||||||
<< "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: " << "collected warning";
|
<< "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: "
|
||||||
|
<< "collected warning";
|
||||||
LOG_TO_SINK_BUT_NOT_TO_LOGFILE(&sink, ERROR)
|
LOG_TO_SINK_BUT_NOT_TO_LOGFILE(&sink, ERROR)
|
||||||
<< "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: " << "collected error";
|
<< "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: "
|
||||||
|
<< "collected error";
|
||||||
|
|
||||||
LOG_TO_SINK_BUT_NOT_TO_LOGFILE(no_sink, INFO)
|
LOG_TO_SINK_BUT_NOT_TO_LOGFILE(no_sink, INFO)
|
||||||
<< "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: " << "thrashed info";
|
<< "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: "
|
||||||
|
<< "thrashed info";
|
||||||
LOG_TO_SINK_BUT_NOT_TO_LOGFILE(no_sink, WARNING)
|
LOG_TO_SINK_BUT_NOT_TO_LOGFILE(no_sink, WARNING)
|
||||||
<< "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: " << "thrashed warning";
|
<< "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: "
|
||||||
|
<< "thrashed warning";
|
||||||
LOG_TO_SINK_BUT_NOT_TO_LOGFILE(nullptr, ERROR)
|
LOG_TO_SINK_BUT_NOT_TO_LOGFILE(nullptr, ERROR)
|
||||||
<< "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: "
|
<< "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: "
|
||||||
<< "thrashed error";
|
<< "thrashed error";
|
||||||
@ -608,10 +639,7 @@ void TestLogSink() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// For testing using CHECK*() on anonymous enums.
|
// For testing using CHECK*() on anonymous enums.
|
||||||
enum {
|
enum { CASE_A, CASE_B };
|
||||||
CASE_A,
|
|
||||||
CASE_B
|
|
||||||
};
|
|
||||||
|
|
||||||
void TestCHECK() {
|
void TestCHECK() {
|
||||||
// Tests using CHECK*() on int values.
|
// Tests using CHECK*() on int values.
|
||||||
@ -641,9 +669,9 @@ void TestCHECK() {
|
|||||||
|
|
||||||
void TestDCHECK() {
|
void TestDCHECK() {
|
||||||
#if defined(NDEBUG)
|
#if defined(NDEBUG)
|
||||||
DCHECK( 1 == 2 ) << " DCHECK's shouldn't be compiled in normal mode";
|
DCHECK(1 == 2) << " DCHECK's shouldn't be compiled in normal mode";
|
||||||
#endif
|
#endif
|
||||||
DCHECK( 1 == 1 );
|
DCHECK(1 == 1);
|
||||||
DCHECK_EQ(1, 1);
|
DCHECK_EQ(1, 1);
|
||||||
DCHECK_NE(1, 2);
|
DCHECK_NE(1, 2);
|
||||||
DCHECK_GE(1, 1);
|
DCHECK_GE(1, 1);
|
||||||
@ -668,9 +696,8 @@ void TestSTREQ() {
|
|||||||
CHECK_STRNE("this", nullptr);
|
CHECK_STRNE("this", nullptr);
|
||||||
CHECK_STRCASENE("this", "that");
|
CHECK_STRCASENE("this", "that");
|
||||||
CHECK_STRCASENE(nullptr, "that");
|
CHECK_STRCASENE(nullptr, "that");
|
||||||
CHECK_STREQ((string("a")+"b").c_str(), "ab");
|
CHECK_STREQ((string("a") + "b").c_str(), "ab");
|
||||||
CHECK_STREQ(string("test").c_str(),
|
CHECK_STREQ(string("test").c_str(), (string("te") + string("st")).c_str());
|
||||||
(string("te") + string("st")).c_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(DeathSTREQ, logging) {
|
TEST(DeathSTREQ, logging) {
|
||||||
@ -680,18 +707,18 @@ TEST(DeathSTREQ, logging) {
|
|||||||
ASSERT_DEATH(CHECK_STRCASEEQ("this", "siht"), "");
|
ASSERT_DEATH(CHECK_STRCASEEQ("this", "siht"), "");
|
||||||
ASSERT_DEATH(CHECK_STRNE(nullptr, nullptr), "");
|
ASSERT_DEATH(CHECK_STRNE(nullptr, nullptr), "");
|
||||||
ASSERT_DEATH(CHECK_STRNE("this", "this"), "");
|
ASSERT_DEATH(CHECK_STRNE("this", "this"), "");
|
||||||
ASSERT_DEATH(CHECK_STREQ((string("a")+"b").c_str(), "abc"), "");
|
ASSERT_DEATH(CHECK_STREQ((string("a") + "b").c_str(), "abc"), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(CheckNOTNULL, Simple) {
|
TEST(CheckNOTNULL, Simple) {
|
||||||
int64 t;
|
int64 t;
|
||||||
void *ptr = static_cast<void *>(&t);
|
void* ptr = static_cast<void*>(&t);
|
||||||
void *ref = CHECK_NOTNULL(ptr);
|
void* ref = CHECK_NOTNULL(ptr);
|
||||||
EXPECT_EQ(ptr, ref);
|
EXPECT_EQ(ptr, ref);
|
||||||
CHECK_NOTNULL(reinterpret_cast<char *>(ptr));
|
CHECK_NOTNULL(reinterpret_cast<char*>(ptr));
|
||||||
CHECK_NOTNULL(reinterpret_cast<unsigned char *>(ptr));
|
CHECK_NOTNULL(reinterpret_cast<unsigned char*>(ptr));
|
||||||
CHECK_NOTNULL(reinterpret_cast<int *>(ptr));
|
CHECK_NOTNULL(reinterpret_cast<int*>(ptr));
|
||||||
CHECK_NOTNULL(reinterpret_cast<int64 *>(ptr));
|
CHECK_NOTNULL(reinterpret_cast<int64*>(ptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(DeathCheckNN, Simple) {
|
TEST(DeathCheckNN, Simple) {
|
||||||
@ -728,7 +755,7 @@ static void GetFiles(const string& pattern, vector<string>* files) {
|
|||||||
LOG_SYSRESULT(GetLastError());
|
LOG_SYSRESULT(GetLastError());
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
# error There is no way to do glob.
|
# error There is no way to do glob.
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -741,8 +768,9 @@ static void DeleteFiles(const string& pattern) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//check string is in file (or is *NOT*, depending on optional checkInFileOrNot)
|
// check string is in file (or is *NOT*, depending on optional checkInFileOrNot)
|
||||||
static void CheckFile(const string& name, const string& expected_string, const bool checkInFileOrNot = true) {
|
static void CheckFile(const string& name, const string& expected_string,
|
||||||
|
const bool checkInFileOrNot = true) {
|
||||||
vector<string> files;
|
vector<string> files;
|
||||||
GetFiles(name + "*", &files);
|
GetFiles(name + "*", &files);
|
||||||
CHECK_EQ(files.size(), 1UL);
|
CHECK_EQ(files.size(), 1UL);
|
||||||
@ -760,7 +788,8 @@ static void CheckFile(const string& name, const string& expected_string, const b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fclose(file);
|
fclose(file);
|
||||||
LOG(FATAL) << "Did " << (checkInFileOrNot? "not " : "") << "find " << expected_string << " in " << files[0];
|
LOG(FATAL) << "Did " << (checkInFileOrNot ? "not " : "") << "find "
|
||||||
|
<< expected_string << " in " << files[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void TestBasename() {
|
static void TestBasename() {
|
||||||
@ -780,8 +809,11 @@ static void TestBasename() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void TestBasenameAppendWhenNoTimestamp() {
|
static void TestBasenameAppendWhenNoTimestamp() {
|
||||||
fprintf(stderr, "==== Test setting log file basename without timestamp and appending properly\n");
|
fprintf(stderr,
|
||||||
const string dest = FLAGS_test_tmpdir + "/logging_test_basename_append_when_no_timestamp";
|
"==== Test setting log file basename without timestamp and appending "
|
||||||
|
"properly\n");
|
||||||
|
const string dest =
|
||||||
|
FLAGS_test_tmpdir + "/logging_test_basename_append_when_no_timestamp";
|
||||||
DeleteFiles(dest + "*");
|
DeleteFiles(dest + "*");
|
||||||
|
|
||||||
ofstream out(dest.c_str());
|
ofstream out(dest.c_str());
|
||||||
@ -790,13 +822,13 @@ static void TestBasenameAppendWhenNoTimestamp() {
|
|||||||
|
|
||||||
CheckFile(dest, "test preexisting content");
|
CheckFile(dest, "test preexisting content");
|
||||||
|
|
||||||
FLAGS_timestamp_in_logfile_name=false;
|
FLAGS_timestamp_in_logfile_name = false;
|
||||||
SetLogDestination(GLOG_INFO, dest.c_str());
|
SetLogDestination(GLOG_INFO, dest.c_str());
|
||||||
LOG(INFO) << "message to new base, appending to preexisting file";
|
LOG(INFO) << "message to new base, appending to preexisting file";
|
||||||
FlushLogFiles(GLOG_INFO);
|
FlushLogFiles(GLOG_INFO);
|
||||||
FLAGS_timestamp_in_logfile_name=true;
|
FLAGS_timestamp_in_logfile_name = true;
|
||||||
|
|
||||||
//if the logging overwrites the file instead of appending it will fail.
|
// if the logging overwrites the file instead of appending it will fail.
|
||||||
CheckFile(dest, "test preexisting content");
|
CheckFile(dest, "test preexisting content");
|
||||||
CheckFile(dest, "message to new base, appending to preexisting file");
|
CheckFile(dest, "message to new base, appending to preexisting file");
|
||||||
|
|
||||||
@ -806,14 +838,18 @@ static void TestBasenameAppendWhenNoTimestamp() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void TestTwoProcessesWrite() {
|
static void TestTwoProcessesWrite() {
|
||||||
// test only implemented for platforms with fork & wait; the actual implementation relies on flock
|
// test only implemented for platforms with fork & wait; the actual
|
||||||
|
// implementation relies on flock
|
||||||
#if defined(HAVE_SYS_WAIT_H) && defined(HAVE_UNISTD_H) && defined(HAVE_FCNTL)
|
#if defined(HAVE_SYS_WAIT_H) && defined(HAVE_UNISTD_H) && defined(HAVE_FCNTL)
|
||||||
fprintf(stderr, "==== Test setting log file basename and two processes writing - second should fail\n");
|
fprintf(stderr,
|
||||||
const string dest = FLAGS_test_tmpdir + "/logging_test_basename_two_processes_writing";
|
"==== Test setting log file basename and two processes writing - "
|
||||||
|
"second should fail\n");
|
||||||
|
const string dest =
|
||||||
|
FLAGS_test_tmpdir + "/logging_test_basename_two_processes_writing";
|
||||||
DeleteFiles(dest + "*");
|
DeleteFiles(dest + "*");
|
||||||
|
|
||||||
//make both processes write into the same file (easier test)
|
// make both processes write into the same file (easier test)
|
||||||
FLAGS_timestamp_in_logfile_name=false;
|
FLAGS_timestamp_in_logfile_name = false;
|
||||||
SetLogDestination(GLOG_INFO, dest.c_str());
|
SetLogDestination(GLOG_INFO, dest.c_str());
|
||||||
LOG(INFO) << "message to new base, parent";
|
LOG(INFO) << "message to new base, parent";
|
||||||
FlushLogFiles(GLOG_INFO);
|
FlushLogFiles(GLOG_INFO);
|
||||||
@ -821,16 +857,20 @@ static void TestTwoProcessesWrite() {
|
|||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
CHECK_ERR(pid);
|
CHECK_ERR(pid);
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
LOG(INFO) << "message to new base, child - should only appear on STDERR not on the file";
|
LOG(INFO) << "message to new base, child - should only appear on STDERR "
|
||||||
ShutdownGoogleLogging(); //for children proc
|
"not on the file";
|
||||||
|
ShutdownGoogleLogging(); // for children proc
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
} else if (pid > 0) {
|
} else if (pid > 0) {
|
||||||
wait(nullptr);
|
wait(nullptr);
|
||||||
}
|
}
|
||||||
FLAGS_timestamp_in_logfile_name=true;
|
FLAGS_timestamp_in_logfile_name = true;
|
||||||
|
|
||||||
CheckFile(dest, "message to new base, parent");
|
CheckFile(dest, "message to new base, parent");
|
||||||
CheckFile(dest, "message to new base, child - should only appear on STDERR not on the file", false);
|
CheckFile(dest,
|
||||||
|
"message to new base, child - should only appear on STDERR not on "
|
||||||
|
"the file",
|
||||||
|
false);
|
||||||
|
|
||||||
// Release
|
// Release
|
||||||
LogToStderr();
|
LogToStderr();
|
||||||
@ -924,7 +964,7 @@ static void TestErrno() {
|
|||||||
CHECK_EQ(errno, ENOENT);
|
CHECK_EQ(errno, ENOENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void TestOneTruncate(const char *path, uint64 limit, uint64 keep,
|
static void TestOneTruncate(const char* path, uint64 limit, uint64 keep,
|
||||||
size_t dsize, size_t ksize, size_t expect) {
|
size_t dsize, size_t ksize, size_t expect) {
|
||||||
int fd;
|
int fd;
|
||||||
CHECK_ERR(fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0600));
|
CHECK_ERR(fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0600));
|
||||||
@ -992,33 +1032,31 @@ static void TestTruncate() {
|
|||||||
// MacOSX 10.4 doesn't fail in this case.
|
// MacOSX 10.4 doesn't fail in this case.
|
||||||
// Windows doesn't have symlink.
|
// Windows doesn't have symlink.
|
||||||
// Let's just ignore this test for these cases.
|
// Let's just ignore this test for these cases.
|
||||||
#if !defined(GLOG_OS_MACOSX) && !defined(GLOG_OS_WINDOWS)
|
# if !defined(GLOG_OS_MACOSX) && !defined(GLOG_OS_WINDOWS)
|
||||||
// Through a symlink should fail to truncate
|
// Through a symlink should fail to truncate
|
||||||
string linkname = path + ".link";
|
string linkname = path + ".link";
|
||||||
unlink(linkname.c_str());
|
unlink(linkname.c_str());
|
||||||
CHECK_ERR(symlink(path.c_str(), linkname.c_str()));
|
CHECK_ERR(symlink(path.c_str(), linkname.c_str()));
|
||||||
TestOneTruncate(linkname.c_str(), 10, 10, 0, 30, 30);
|
TestOneTruncate(linkname.c_str(), 10, 10, 0, 30, 30);
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
// The /proc/self path makes sense only for linux.
|
// The /proc/self path makes sense only for linux.
|
||||||
#if defined(GLOG_OS_LINUX)
|
# if defined(GLOG_OS_LINUX)
|
||||||
// Through an open fd symlink should work
|
// Through an open fd symlink should work
|
||||||
int fd;
|
int fd;
|
||||||
CHECK_ERR(fd = open(path.c_str(), O_APPEND | O_WRONLY));
|
CHECK_ERR(fd = open(path.c_str(), O_APPEND | O_WRONLY));
|
||||||
char fdpath[64];
|
char fdpath[64];
|
||||||
std::snprintf(fdpath, sizeof(fdpath), "/proc/self/fd/%d", fd);
|
std::snprintf(fdpath, sizeof(fdpath), "/proc/self/fd/%d", fd);
|
||||||
TestOneTruncate(fdpath, 10, 10, 10, 10, 10);
|
TestOneTruncate(fdpath, 10, 10, 10, 10, 10);
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RecordDeletionLogger : public base::Logger {
|
struct RecordDeletionLogger : public base::Logger {
|
||||||
RecordDeletionLogger(bool* set_on_destruction,
|
RecordDeletionLogger(bool* set_on_destruction, base::Logger* wrapped_logger)
|
||||||
base::Logger* wrapped_logger) :
|
: set_on_destruction_(set_on_destruction),
|
||||||
set_on_destruction_(set_on_destruction),
|
wrapped_logger_(wrapped_logger) {
|
||||||
wrapped_logger_(wrapped_logger)
|
|
||||||
{
|
|
||||||
*set_on_destruction_ = false;
|
*set_on_destruction_ = false;
|
||||||
}
|
}
|
||||||
~RecordDeletionLogger() override { *set_on_destruction_ = true; }
|
~RecordDeletionLogger() override { *set_on_destruction_ = true; }
|
||||||
@ -1074,9 +1112,9 @@ std::ostream& operator<<(std::ostream& stream, LogTimeRecorder& t) {
|
|||||||
}
|
}
|
||||||
// get elapsed time in nanoseconds
|
// get elapsed time in nanoseconds
|
||||||
int64 elapsedTime_ns(const std::chrono::steady_clock::time_point& begin,
|
int64 elapsedTime_ns(const std::chrono::steady_clock::time_point& begin,
|
||||||
const std::chrono::steady_clock::time_point& end) {
|
const std::chrono::steady_clock::time_point& end) {
|
||||||
return std::chrono::duration_cast<std::chrono::nanoseconds>((end - begin))
|
return std::chrono::duration_cast<std::chrono::nanoseconds>((end - begin))
|
||||||
.count();
|
.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void TestLogPeriodically() {
|
static void TestLogPeriodically() {
|
||||||
@ -1087,16 +1125,16 @@ static void TestLogPeriodically() {
|
|||||||
constexpr double LOG_PERIOD_SEC = LogTimes::LOG_PERIOD_NS * 1e-9;
|
constexpr double LOG_PERIOD_SEC = LogTimes::LOG_PERIOD_NS * 1e-9;
|
||||||
|
|
||||||
while (timeLogger.m_streamTimes < LogTimes::MAX_CALLS) {
|
while (timeLogger.m_streamTimes < LogTimes::MAX_CALLS) {
|
||||||
LOG_EVERY_T(INFO, LOG_PERIOD_SEC)
|
LOG_EVERY_T(INFO, LOG_PERIOD_SEC)
|
||||||
<< timeLogger << "Timed Message #" << timeLogger.m_streamTimes;
|
<< timeLogger << "Timed Message #" << timeLogger.m_streamTimes;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate time between each call in nanoseconds for higher resolution to
|
// Calculate time between each call in nanoseconds for higher resolution to
|
||||||
// minimize error.
|
// minimize error.
|
||||||
int64 nsBetweenCalls[LogTimes::MAX_CALLS - 1];
|
int64 nsBetweenCalls[LogTimes::MAX_CALLS - 1];
|
||||||
for (size_t i = 1; i < LogTimes::MAX_CALLS; ++i) {
|
for (size_t i = 1; i < LogTimes::MAX_CALLS; ++i) {
|
||||||
nsBetweenCalls[i - 1] = elapsedTime_ns(
|
nsBetweenCalls[i - 1] = elapsedTime_ns(timeLogger.m_callTimes[i - 1],
|
||||||
timeLogger.m_callTimes[i - 1], timeLogger.m_callTimes[i]);
|
timeLogger.m_callTimes[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (long time_ns : nsBetweenCalls) {
|
for (long time_ns : nsBetweenCalls) {
|
||||||
@ -1107,17 +1145,18 @@ static void TestLogPeriodically() {
|
|||||||
namespace google {
|
namespace google {
|
||||||
namespace glog_internal_namespace_ {
|
namespace glog_internal_namespace_ {
|
||||||
extern // in logging.cc
|
extern // in logging.cc
|
||||||
bool SafeFNMatch_(const char* pattern, size_t patt_len,
|
bool
|
||||||
const char* str, size_t str_len);
|
SafeFNMatch_(const char* pattern, size_t patt_len, const char* str,
|
||||||
} // namespace glog_internal_namespace_
|
size_t str_len);
|
||||||
|
} // namespace glog_internal_namespace_
|
||||||
using glog_internal_namespace_::SafeFNMatch_;
|
using glog_internal_namespace_::SafeFNMatch_;
|
||||||
} // namespace google
|
} // namespace google
|
||||||
|
|
||||||
static bool WrapSafeFNMatch(string pattern, string str) {
|
static bool WrapSafeFNMatch(string pattern, string str) {
|
||||||
pattern += "abc";
|
pattern += "abc";
|
||||||
str += "defgh";
|
str += "defgh";
|
||||||
return SafeFNMatch_(pattern.data(), pattern.size() - 3,
|
return SafeFNMatch_(pattern.data(), pattern.size() - 3, str.data(),
|
||||||
str.data(), str.size() - 5);
|
str.size() - 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(SafeFNMatch, logging) {
|
TEST(SafeFNMatch, logging) {
|
||||||
@ -1184,7 +1223,6 @@ class TestLogSinkWriter : public Thread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// helpers ---------------
|
// helpers ---------------
|
||||||
|
|
||||||
// For creating a "Condition".
|
// For creating a "Condition".
|
||||||
@ -1239,7 +1277,6 @@ class TestLogSinkWriter : public Thread {
|
|||||||
// (that other thread can than use LOG() itself),
|
// (that other thread can than use LOG() itself),
|
||||||
class TestWaitingLogSink : public LogSink {
|
class TestWaitingLogSink : public LogSink {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
TestWaitingLogSink() {
|
TestWaitingLogSink() {
|
||||||
tid_ = pthread_self(); // for thread-specific behavior
|
tid_ = pthread_self(); // for thread-specific behavior
|
||||||
AddLogSink(this);
|
AddLogSink(this);
|
||||||
@ -1260,18 +1297,17 @@ class TestWaitingLogSink : public LogSink {
|
|||||||
// Note: Something like ThreadLocalLogSink is a better choice
|
// Note: Something like ThreadLocalLogSink is a better choice
|
||||||
// to do thread-specific LogSink logic for real.
|
// to do thread-specific LogSink logic for real.
|
||||||
if (pthread_equal(tid_, pthread_self())) {
|
if (pthread_equal(tid_, pthread_self())) {
|
||||||
writer_.Buffer(ToString(severity, base_filename, line,
|
writer_.Buffer(ToString(severity, base_filename, line, logmsgtime,
|
||||||
logmsgtime, message, message_len));
|
message, message_len));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaitTillSent() override {
|
void WaitTillSent() override {
|
||||||
// Wait for Writer thread if we are the original logging thread.
|
// Wait for Writer thread if we are the original logging thread.
|
||||||
if (pthread_equal(tid_, pthread_self())) writer_.Wait();
|
if (pthread_equal(tid_, pthread_self())) writer_.Wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
pthread_t tid_;
|
pthread_t tid_;
|
||||||
TestLogSinkWriter writer_;
|
TestLogSinkWriter writer_;
|
||||||
};
|
};
|
||||||
@ -1282,7 +1318,8 @@ static void TestLogSinkWaitTillSent() {
|
|||||||
// Clear global_messages here to make sure that this test case can be
|
// Clear global_messages here to make sure that this test case can be
|
||||||
// reentered
|
// reentered
|
||||||
global_messages.clear();
|
global_messages.clear();
|
||||||
{ TestWaitingLogSink sink;
|
{
|
||||||
|
TestWaitingLogSink sink;
|
||||||
// Sleeps give the sink threads time to do all their work,
|
// Sleeps give the sink threads time to do all their work,
|
||||||
// so that we get a reliable log capture to compare to the golden file.
|
// so that we get a reliable log capture to compare to the golden file.
|
||||||
LOG(INFO) << "Message 1";
|
LOG(INFO) << "Message 1";
|
||||||
@ -1300,15 +1337,16 @@ static void TestLogSinkWaitTillSent() {
|
|||||||
|
|
||||||
TEST(Strerror, logging) {
|
TEST(Strerror, logging) {
|
||||||
int errcode = EINTR;
|
int errcode = EINTR;
|
||||||
char *msg = strdup(strerror(errcode));
|
char* msg = strdup(strerror(errcode));
|
||||||
const size_t buf_size = strlen(msg) + 1;
|
const size_t buf_size = strlen(msg) + 1;
|
||||||
char *buf = new char[buf_size];
|
char* buf = new char[buf_size];
|
||||||
CHECK_EQ(posix_strerror_r(errcode, nullptr, 0), -1);
|
CHECK_EQ(posix_strerror_r(errcode, nullptr, 0), -1);
|
||||||
buf[0] = 'A';
|
buf[0] = 'A';
|
||||||
CHECK_EQ(posix_strerror_r(errcode, buf, 0), -1);
|
CHECK_EQ(posix_strerror_r(errcode, buf, 0), -1);
|
||||||
CHECK_EQ(buf[0], 'A');
|
CHECK_EQ(buf[0], 'A');
|
||||||
CHECK_EQ(posix_strerror_r(errcode, nullptr, buf_size), -1);
|
CHECK_EQ(posix_strerror_r(errcode, nullptr, buf_size), -1);
|
||||||
#if defined(GLOG_OS_MACOSX) || defined(GLOG_OS_FREEBSD) || defined(GLOG_OS_OPENBSD)
|
#if defined(GLOG_OS_MACOSX) || defined(GLOG_OS_FREEBSD) || \
|
||||||
|
defined(GLOG_OS_OPENBSD)
|
||||||
// MacOSX or FreeBSD considers this case is an error since there is
|
// MacOSX or FreeBSD considers this case is an error since there is
|
||||||
// no enough space.
|
// no enough space.
|
||||||
CHECK_EQ(posix_strerror_r(errcode, buf, 1), -1);
|
CHECK_EQ(posix_strerror_r(errcode, buf, 1), -1);
|
||||||
@ -1338,12 +1376,12 @@ static void MyCheck(bool a, bool b) {
|
|||||||
TEST(DVLog, Basic) {
|
TEST(DVLog, Basic) {
|
||||||
ScopedMockLog log;
|
ScopedMockLog log;
|
||||||
|
|
||||||
#if defined(NDEBUG)
|
# if defined(NDEBUG)
|
||||||
// We are expecting that nothing is logged.
|
// We are expecting that nothing is logged.
|
||||||
EXPECT_CALL(log, Log(_, _, _)).Times(0);
|
EXPECT_CALL(log, Log(_, _, _)).Times(0);
|
||||||
#else
|
# else
|
||||||
EXPECT_CALL(log, Log(GLOG_INFO, __FILE__, "debug log"));
|
EXPECT_CALL(log, Log(GLOG_INFO, __FILE__, "debug log"));
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
FLAGS_v = 1;
|
FLAGS_v = 1;
|
||||||
DVLOG(1) << "debug log";
|
DVLOG(1) << "debug log";
|
||||||
@ -1385,15 +1423,15 @@ TEST(TestExitOnDFatal, ToBeOrNotToBe) {
|
|||||||
// We don't die.
|
// We don't die.
|
||||||
{
|
{
|
||||||
ScopedMockLog log;
|
ScopedMockLog log;
|
||||||
//EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber());
|
// EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber());
|
||||||
// LOG(DFATAL) has severity FATAL if debugging, but is
|
// LOG(DFATAL) has severity FATAL if debugging, but is
|
||||||
// downgraded to ERROR if not debugging.
|
// downgraded to ERROR if not debugging.
|
||||||
const LogSeverity severity =
|
const LogSeverity severity =
|
||||||
#if defined(NDEBUG)
|
# if defined(NDEBUG)
|
||||||
GLOG_ERROR;
|
GLOG_ERROR;
|
||||||
#else
|
# else
|
||||||
GLOG_FATAL;
|
GLOG_FATAL;
|
||||||
#endif
|
# endif
|
||||||
EXPECT_CALL(log, Log(severity, __FILE__, "This should not be fatal"));
|
EXPECT_CALL(log, Log(severity, __FILE__, "This should not be fatal"));
|
||||||
LOG(DFATAL) << "This should not be fatal";
|
LOG(DFATAL) << "This should not be fatal";
|
||||||
}
|
}
|
||||||
@ -1402,20 +1440,19 @@ TEST(TestExitOnDFatal, ToBeOrNotToBe) {
|
|||||||
base::internal::SetExitOnDFatal(true);
|
base::internal::SetExitOnDFatal(true);
|
||||||
EXPECT_TRUE(base::internal::GetExitOnDFatal());
|
EXPECT_TRUE(base::internal::GetExitOnDFatal());
|
||||||
|
|
||||||
#ifdef GTEST_HAS_DEATH_TEST
|
# ifdef GTEST_HAS_DEATH_TEST
|
||||||
// Death comes on little cats' feet.
|
// Death comes on little cats' feet.
|
||||||
EXPECT_DEBUG_DEATH({
|
EXPECT_DEBUG_DEATH({ LOG(DFATAL) << "This should be fatal in debug mode"; },
|
||||||
LOG(DFATAL) << "This should be fatal in debug mode";
|
"This should be fatal in debug mode");
|
||||||
}, "This should be fatal in debug mode");
|
# endif
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_STACKTRACE
|
# ifdef HAVE_STACKTRACE
|
||||||
|
|
||||||
static void BacktraceAtHelper() {
|
static void BacktraceAtHelper() {
|
||||||
LOG(INFO) << "Not me";
|
LOG(INFO) << "Not me";
|
||||||
|
|
||||||
// The vertical spacing of the next 3 lines is significant.
|
// The vertical spacing of the next 3 lines is significant.
|
||||||
LOG(INFO) << "Backtrace me";
|
LOG(INFO) << "Backtrace me";
|
||||||
}
|
}
|
||||||
static int kBacktraceAtLine = __LINE__ - 2; // The line of the LOG(INFO) above
|
static int kBacktraceAtLine = __LINE__ - 2; // The line of the LOG(INFO) above
|
||||||
@ -1443,19 +1480,19 @@ TEST(LogBacktraceAt, DoesBacktraceAtRightLineWhenEnabled) {
|
|||||||
// the name of the containing function, followed by the log message.
|
// the name of the containing function, followed by the log message.
|
||||||
// We use HasSubstr()s instead of ContainsRegex() for environments
|
// We use HasSubstr()s instead of ContainsRegex() for environments
|
||||||
// which don't have regexp.
|
// which don't have regexp.
|
||||||
EXPECT_CALL(log, Log(_, _, AllOf(HasSubstr("stacktrace:"),
|
EXPECT_CALL(
|
||||||
HasSubstr("BacktraceAtHelper"),
|
log, Log(_, _,
|
||||||
HasSubstr("main"),
|
AllOf(HasSubstr("stacktrace:"), HasSubstr("BacktraceAtHelper"),
|
||||||
HasSubstr("Backtrace me"))));
|
HasSubstr("main"), HasSubstr("Backtrace me"))));
|
||||||
// Other LOGs should not include a backtrace.
|
// Other LOGs should not include a backtrace.
|
||||||
EXPECT_CALL(log, Log(_, _, "Not me"));
|
EXPECT_CALL(log, Log(_, _, "Not me"));
|
||||||
|
|
||||||
BacktraceAtHelper();
|
BacktraceAtHelper();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // HAVE_STACKTRACE
|
# endif // HAVE_STACKTRACE
|
||||||
|
|
||||||
#endif // HAVE_LIB_GMOCK
|
#endif // HAVE_LIB_GMOCK
|
||||||
|
|
||||||
struct UserDefinedClass {
|
struct UserDefinedClass {
|
||||||
bool operator==(const UserDefinedClass&) const { return true; }
|
bool operator==(const UserDefinedClass&) const { return true; }
|
||||||
@ -1480,7 +1517,8 @@ TEST(UserDefinedClass, logging) {
|
|||||||
TEST(LogMsgTime, gmtoff) {
|
TEST(LogMsgTime, gmtoff) {
|
||||||
/*
|
/*
|
||||||
* Unit test for GMT offset API
|
* Unit test for GMT offset API
|
||||||
* TODO: To properly test this API, we need a platform independent way to set time-zone.
|
* TODO: To properly test this API, we need a platform independent way to set
|
||||||
|
* time-zone.
|
||||||
* */
|
* */
|
||||||
google::LogMessage log_obj(__FILE__, __LINE__);
|
google::LogMessage log_obj(__FILE__, __LINE__);
|
||||||
|
|
||||||
@ -1488,21 +1526,23 @@ TEST(LogMsgTime, gmtoff) {
|
|||||||
// GMT offset ranges from UTC-12:00 to UTC+14:00
|
// GMT offset ranges from UTC-12:00 to UTC+14:00
|
||||||
const long utc_min_offset = -43200;
|
const long utc_min_offset = -43200;
|
||||||
const long utc_max_offset = 50400;
|
const long utc_max_offset = 50400;
|
||||||
EXPECT_TRUE( (nGmtOff >= utc_min_offset) && (nGmtOff <= utc_max_offset) );
|
EXPECT_TRUE((nGmtOff >= utc_min_offset) && (nGmtOff <= utc_max_offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(EmailLogging, ValidAddress) {
|
TEST(EmailLogging, ValidAddress) {
|
||||||
FlagSaver saver;
|
FlagSaver saver;
|
||||||
FLAGS_logmailer = "/usr/bin/true";
|
FLAGS_logmailer = "/usr/bin/true";
|
||||||
|
|
||||||
EXPECT_TRUE(SendEmail("example@example.com", "Example subject", "Example body"));
|
EXPECT_TRUE(
|
||||||
|
SendEmail("example@example.com", "Example subject", "Example body"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(EmailLogging, MultipleAddresses) {
|
TEST(EmailLogging, MultipleAddresses) {
|
||||||
FlagSaver saver;
|
FlagSaver saver;
|
||||||
FLAGS_logmailer = "/usr/bin/true";
|
FLAGS_logmailer = "/usr/bin/true";
|
||||||
|
|
||||||
EXPECT_TRUE(SendEmail("example@example.com,foo@bar.com", "Example subject", "Example body"));
|
EXPECT_TRUE(SendEmail("example@example.com,foo@bar.com", "Example subject",
|
||||||
|
"Example body"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(EmailLogging, InvalidAddress) {
|
TEST(EmailLogging, InvalidAddress) {
|
||||||
@ -1516,5 +1556,6 @@ TEST(EmailLogging, MaliciousAddress) {
|
|||||||
FlagSaver saver;
|
FlagSaver saver;
|
||||||
FLAGS_logmailer = "/usr/bin/true";
|
FLAGS_logmailer = "/usr/bin/true";
|
||||||
|
|
||||||
EXPECT_FALSE(SendEmail("!/bin/true@example.com", "Example subject", "Example body"));
|
EXPECT_FALSE(
|
||||||
|
SendEmail("!/bin/true@example.com", "Example subject", "Example body"));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,11 +33,11 @@
|
|||||||
|
|
||||||
#include "mock-log.h"
|
#include "mock-log.h"
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include <gmock/gmock.h>
|
#include <gmock/gmock.h>
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
using google::GLOG_ERROR;
|
using google::GLOG_ERROR;
|
||||||
@ -57,8 +57,7 @@ TEST(ScopedMockLogTest, InterceptsLog) {
|
|||||||
InSequence s;
|
InSequence s;
|
||||||
EXPECT_CALL(log,
|
EXPECT_CALL(log,
|
||||||
Log(GLOG_WARNING, EndsWith("mock-log_unittest.cc"), "Fishy."));
|
Log(GLOG_WARNING, EndsWith("mock-log_unittest.cc"), "Fishy."));
|
||||||
EXPECT_CALL(log, Log(GLOG_INFO, _, "Working..."))
|
EXPECT_CALL(log, Log(GLOG_INFO, _, "Working...")).Times(2);
|
||||||
.Times(2);
|
|
||||||
EXPECT_CALL(log, Log(GLOG_ERROR, _, "Bad!!"));
|
EXPECT_CALL(log, Log(GLOG_ERROR, _, "Bad!!"));
|
||||||
|
|
||||||
LOG(WARNING) << "Fishy.";
|
LOG(WARNING) << "Fishy.";
|
||||||
@ -67,13 +66,9 @@ TEST(ScopedMockLogTest, InterceptsLog) {
|
|||||||
LOG(ERROR) << "Bad!!";
|
LOG(ERROR) << "Bad!!";
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogBranch() {
|
void LogBranch() { LOG(INFO) << "Logging a branch..."; }
|
||||||
LOG(INFO) << "Logging a branch...";
|
|
||||||
}
|
|
||||||
|
|
||||||
void LogTree() {
|
void LogTree() { LOG(INFO) << "Logging the whole tree..."; }
|
||||||
LOG(INFO) << "Logging the whole tree...";
|
|
||||||
}
|
|
||||||
|
|
||||||
void LogForest() {
|
void LogForest() {
|
||||||
LOG(INFO) << "Logging the entire forest.";
|
LOG(INFO) << "Logging the entire forest.";
|
||||||
@ -99,7 +94,7 @@ TEST(ScopedMockLogTest, LogDuringIntercept) {
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char** argv) {
|
||||||
google::InitGoogleLogging(argv[0]);
|
google::InitGoogleLogging(argv[0]);
|
||||||
testing::InitGoogleTest(&argc, argv);
|
testing::InitGoogleTest(&argc, argv);
|
||||||
testing::InitGoogleMock(&argc, argv);
|
testing::InitGoogleMock(&argc, argv);
|
||||||
|
|||||||
@ -1,6 +1,3 @@
|
|||||||
#include "glog/logging.h"
|
#include "glog/logging.h"
|
||||||
|
|
||||||
int main(int /*argc*/, char** argv)
|
int main(int /*argc*/, char** argv) { google::InitGoogleLogging(argv[0]); }
|
||||||
{
|
|
||||||
google::InitGoogleLogging(argv[0]);
|
|
||||||
}
|
|
||||||
|
|||||||
@ -37,7 +37,7 @@
|
|||||||
|
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
# include <unistd.h> // for close() and write()
|
# include <unistd.h> // for close() and write()
|
||||||
#endif
|
#endif
|
||||||
#include <fcntl.h> // for open()
|
#include <fcntl.h> // for open()
|
||||||
|
|
||||||
@ -49,37 +49,37 @@
|
|||||||
#include "glog/raw_logging.h"
|
#include "glog/raw_logging.h"
|
||||||
|
|
||||||
#ifdef HAVE_STACKTRACE
|
#ifdef HAVE_STACKTRACE
|
||||||
# include "stacktrace.h"
|
# include "stacktrace.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(HAVE_SYSCALL_H)
|
#if defined(HAVE_SYSCALL_H)
|
||||||
#include <syscall.h> // for syscall()
|
# include <syscall.h> // for syscall()
|
||||||
#elif defined(HAVE_SYS_SYSCALL_H)
|
#elif defined(HAVE_SYS_SYSCALL_H)
|
||||||
#include <sys/syscall.h> // for syscall()
|
# include <sys/syscall.h> // for syscall()
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (defined(HAVE_SYSCALL_H) || defined(HAVE_SYS_SYSCALL_H)) && \
|
#if (defined(HAVE_SYSCALL_H) || defined(HAVE_SYS_SYSCALL_H)) && \
|
||||||
(!(defined(GLOG_OS_MACOSX)) && !(defined(GLOG_OS_OPENBSD))) && \
|
(!(defined(GLOG_OS_MACOSX)) && !(defined(GLOG_OS_OPENBSD))) && \
|
||||||
!defined(GLOG_OS_EMSCRIPTEN)
|
!defined(GLOG_OS_EMSCRIPTEN)
|
||||||
#define safe_write(fd, s, len) syscall(SYS_write, fd, s, len)
|
# define safe_write(fd, s, len) syscall(SYS_write, fd, s, len)
|
||||||
#else
|
#else
|
||||||
// Not so safe, but what can you do?
|
// Not so safe, but what can you do?
|
||||||
#define safe_write(fd, s, len) write(fd, s, len)
|
# define safe_write(fd, s, len) write(fd, s, len)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace google {
|
namespace google {
|
||||||
|
|
||||||
#if defined(__GNUC__)
|
#if defined(__GNUC__)
|
||||||
#define GLOG_ATTRIBUTE_FORMAT(archetype, stringIndex, firstToCheck) \
|
# define GLOG_ATTRIBUTE_FORMAT(archetype, stringIndex, firstToCheck) \
|
||||||
__attribute__((format(archetype, stringIndex, firstToCheck)))
|
__attribute__((format(archetype, stringIndex, firstToCheck)))
|
||||||
#define GLOG_ATTRIBUTE_FORMAT_ARG(stringIndex) \
|
# define GLOG_ATTRIBUTE_FORMAT_ARG(stringIndex) \
|
||||||
__attribute__((format_arg(stringIndex)))
|
__attribute__((format_arg(stringIndex)))
|
||||||
#else
|
#else
|
||||||
#define GLOG_ATTRIBUTE_FORMAT(archetype, stringIndex, firstToCheck)
|
# define GLOG_ATTRIBUTE_FORMAT(archetype, stringIndex, firstToCheck)
|
||||||
#define GLOG_ATTRIBUTE_FORMAT_ARG(stringIndex)
|
# define GLOG_ATTRIBUTE_FORMAT_ARG(stringIndex)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// CAVEAT: std::vsnprintf called from *DoRawLog below has some (exotic) code
|
// CAVEAT: std::vsnprintf called from *DoRawLog below has some (exotic) code
|
||||||
@ -103,15 +103,15 @@ static bool DoRawLog(char** buf, size_t* size, const char* format, ...) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Helper for RawLog__ below.
|
// Helper for RawLog__ below.
|
||||||
inline static bool VADoRawLog(char** buf, size_t* size,
|
inline static bool VADoRawLog(char** buf, size_t* size, const char* format,
|
||||||
const char* format, va_list ap) {
|
va_list ap) {
|
||||||
#if defined(__GNUC__)
|
#if defined(__GNUC__)
|
||||||
#pragma GCC diagnostic push
|
# pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
|
# pragma GCC diagnostic ignored "-Wformat-nonliteral"
|
||||||
#endif
|
#endif
|
||||||
int n = std::vsnprintf(*buf, *size, format, ap);
|
int n = std::vsnprintf(*buf, *size, format, ap);
|
||||||
#if defined(__GNUC__)
|
#if defined(__GNUC__)
|
||||||
#pragma GCC diagnostic pop
|
# pragma GCC diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
if (n < 0 || static_cast<size_t>(n) > *size) return false;
|
if (n < 0 || static_cast<size_t>(n) > *size) return false;
|
||||||
*size -= static_cast<size_t>(n);
|
*size -= static_cast<size_t>(n);
|
||||||
@ -122,7 +122,7 @@ inline static bool VADoRawLog(char** buf, size_t* size,
|
|||||||
static const int kLogBufSize = 3000;
|
static const int kLogBufSize = 3000;
|
||||||
static bool crashed = false;
|
static bool crashed = false;
|
||||||
static CrashReason crash_reason;
|
static CrashReason crash_reason;
|
||||||
static char crash_buf[kLogBufSize + 1] = { 0 }; // Will end in '\0'
|
static char crash_buf[kLogBufSize + 1] = {0}; // Will end in '\0'
|
||||||
|
|
||||||
GLOG_ATTRIBUTE_FORMAT(printf, 4, 5)
|
GLOG_ATTRIBUTE_FORMAT(printf, 4, 5)
|
||||||
void RawLog__(LogSeverity severity, const char* file, int line,
|
void RawLog__(LogSeverity severity, const char* file, int line,
|
||||||
@ -139,9 +139,8 @@ void RawLog__(LogSeverity severity, const char* file, int line,
|
|||||||
|
|
||||||
// NOTE: this format should match the specification in base/logging.h
|
// NOTE: this format should match the specification in base/logging.h
|
||||||
DoRawLog(&buf, &size, "%c00000000 00:00:00.000000 %5u %s:%d] RAW: ",
|
DoRawLog(&buf, &size, "%c00000000 00:00:00.000000 %5u %s:%d] RAW: ",
|
||||||
LogSeverityNames[severity][0],
|
LogSeverityNames[severity][0], static_cast<unsigned int>(GetTID()),
|
||||||
static_cast<unsigned int>(GetTID()),
|
const_basename(const_cast<char*>(file)), line);
|
||||||
const_basename(const_cast<char *>(file)), line);
|
|
||||||
|
|
||||||
// Record the position and size of the buffer after the prefix
|
// Record the position and size of the buffer after the prefix
|
||||||
const char* msg_start = buf;
|
const char* msg_start = buf;
|
||||||
@ -161,7 +160,7 @@ void RawLog__(LogSeverity severity, const char* file, int line,
|
|||||||
// libc (to side-step any libc interception).
|
// libc (to side-step any libc interception).
|
||||||
// We write just once to avoid races with other invocations of RawLog__.
|
// We write just once to avoid races with other invocations of RawLog__.
|
||||||
safe_write(STDERR_FILENO, buffer, strlen(buffer));
|
safe_write(STDERR_FILENO, buffer, strlen(buffer));
|
||||||
if (severity == GLOG_FATAL) {
|
if (severity == GLOG_FATAL) {
|
||||||
if (!sync_val_compare_and_swap(&crashed, false, true)) {
|
if (!sync_val_compare_and_swap(&crashed, false, true)) {
|
||||||
crash_reason.filename = file;
|
crash_reason.filename = file;
|
||||||
crash_reason.line_number = line;
|
crash_reason.line_number = line;
|
||||||
|
|||||||
@ -41,13 +41,13 @@
|
|||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
|
||||||
#ifdef HAVE_UCONTEXT_H
|
#ifdef HAVE_UCONTEXT_H
|
||||||
# include <ucontext.h>
|
# include <ucontext.h>
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_SYS_UCONTEXT_H
|
#ifdef HAVE_SYS_UCONTEXT_H
|
||||||
# include <sys/ucontext.h>
|
# include <sys/ucontext.h>
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
#include <unistd.h>
|
# include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace google {
|
namespace google {
|
||||||
@ -61,16 +61,14 @@ namespace {
|
|||||||
// The list should be synced with the comment in signalhandler.h.
|
// The list should be synced with the comment in signalhandler.h.
|
||||||
const struct {
|
const struct {
|
||||||
int number;
|
int number;
|
||||||
const char *name;
|
const char* name;
|
||||||
} kFailureSignals[] = {
|
} kFailureSignals[] = {
|
||||||
{ SIGSEGV, "SIGSEGV" },
|
{SIGSEGV, "SIGSEGV"}, {SIGILL, "SIGILL"},
|
||||||
{ SIGILL, "SIGILL" },
|
{SIGFPE, "SIGFPE"}, {SIGABRT, "SIGABRT"},
|
||||||
{ SIGFPE, "SIGFPE" },
|
|
||||||
{ SIGABRT, "SIGABRT" },
|
|
||||||
#if !defined(GLOG_OS_WINDOWS)
|
#if !defined(GLOG_OS_WINDOWS)
|
||||||
{ SIGBUS, "SIGBUS" },
|
{SIGBUS, "SIGBUS"},
|
||||||
#endif
|
#endif
|
||||||
{ SIGTERM, "SIGTERM" },
|
{SIGTERM, "SIGTERM"},
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool kFailureSignalHandlerInstalled = false;
|
static bool kFailureSignalHandlerInstalled = false;
|
||||||
@ -78,14 +76,15 @@ static bool kFailureSignalHandlerInstalled = false;
|
|||||||
#if !defined(GLOG_OS_WINDOWS)
|
#if !defined(GLOG_OS_WINDOWS)
|
||||||
// Returns the program counter from signal context, nullptr if unknown.
|
// Returns the program counter from signal context, nullptr if unknown.
|
||||||
void* GetPC(void* ucontext_in_void) {
|
void* GetPC(void* ucontext_in_void) {
|
||||||
#if (defined(HAVE_UCONTEXT_H) || defined(HAVE_SYS_UCONTEXT_H)) && defined(PC_FROM_UCONTEXT)
|
# if (defined(HAVE_UCONTEXT_H) || defined(HAVE_SYS_UCONTEXT_H)) && \
|
||||||
|
defined(PC_FROM_UCONTEXT)
|
||||||
if (ucontext_in_void != nullptr) {
|
if (ucontext_in_void != nullptr) {
|
||||||
ucontext_t *context = reinterpret_cast<ucontext_t *>(ucontext_in_void);
|
ucontext_t* context = reinterpret_cast<ucontext_t*>(ucontext_in_void);
|
||||||
return (void*)context->PC_FROM_UCONTEXT;
|
return (void*)context->PC_FROM_UCONTEXT;
|
||||||
}
|
}
|
||||||
#else
|
# else
|
||||||
(void)ucontext_in_void;
|
(void)ucontext_in_void;
|
||||||
#endif
|
# endif
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -94,14 +93,13 @@ void* GetPC(void* ucontext_in_void) {
|
|||||||
// as it's not async signal safe.
|
// as it's not async signal safe.
|
||||||
class MinimalFormatter {
|
class MinimalFormatter {
|
||||||
public:
|
public:
|
||||||
MinimalFormatter(char *buffer, size_t size)
|
MinimalFormatter(char* buffer, size_t size)
|
||||||
: buffer_(buffer),
|
: buffer_(buffer), cursor_(buffer), end_(buffer + size) {}
|
||||||
cursor_(buffer),
|
|
||||||
end_(buffer + size) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the number of bytes written in the buffer.
|
// Returns the number of bytes written in the buffer.
|
||||||
std::size_t num_bytes_written() const { return static_cast<std::size_t>(cursor_ - buffer_); }
|
std::size_t num_bytes_written() const {
|
||||||
|
return static_cast<std::size_t>(cursor_ - buffer_);
|
||||||
|
}
|
||||||
|
|
||||||
// Appends string from "str" and updates the internal cursor.
|
// Appends string from "str" and updates the internal cursor.
|
||||||
void AppendString(const char* str) {
|
void AppendString(const char* str) {
|
||||||
@ -147,9 +145,9 @@ class MinimalFormatter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char *buffer_;
|
char* buffer_;
|
||||||
char *cursor_;
|
char* cursor_;
|
||||||
const char * const end_;
|
const char* const end_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Writes the given data with the size to the standard error.
|
// Writes the given data with the size to the standard error.
|
||||||
@ -181,7 +179,7 @@ void DumpTimeInfo() {
|
|||||||
#if defined(HAVE_STACKTRACE) && defined(HAVE_SIGACTION)
|
#if defined(HAVE_STACKTRACE) && defined(HAVE_SIGACTION)
|
||||||
|
|
||||||
// Dumps information about the signal to STDERR.
|
// Dumps information about the signal to STDERR.
|
||||||
void DumpSignalInfo(int signal_number, siginfo_t *siginfo) {
|
void DumpSignalInfo(int signal_number, siginfo_t* siginfo) {
|
||||||
// Get the signal name.
|
// Get the signal name.
|
||||||
const char* signal_name = nullptr;
|
const char* signal_name = nullptr;
|
||||||
for (auto kFailureSignal : kFailureSignals) {
|
for (auto kFailureSignal : kFailureSignals) {
|
||||||
@ -217,11 +215,11 @@ void DumpSignalInfo(int signal_number, siginfo_t *siginfo) {
|
|||||||
reinterpret_cast<uint64>(reinterpret_cast<const char*>(id)), 16);
|
reinterpret_cast<uint64>(reinterpret_cast<const char*>(id)), 16);
|
||||||
formatter.AppendString(") ");
|
formatter.AppendString(") ");
|
||||||
// Only linux has the PID of the signal sender in si_pid.
|
// Only linux has the PID of the signal sender in si_pid.
|
||||||
#ifdef GLOG_OS_LINUX
|
# ifdef GLOG_OS_LINUX
|
||||||
formatter.AppendString("from PID ");
|
formatter.AppendString("from PID ");
|
||||||
formatter.AppendUint64(static_cast<uint64>(siginfo->si_pid), 10);
|
formatter.AppendUint64(static_cast<uint64>(siginfo->si_pid), 10);
|
||||||
formatter.AppendString("; ");
|
formatter.AppendString("; ");
|
||||||
#endif
|
# endif
|
||||||
formatter.AppendString("stack trace: ***\n");
|
formatter.AppendString("stack trace: ***\n");
|
||||||
g_failure_writer(buf, formatter.num_bytes_written());
|
g_failure_writer(buf, formatter.num_bytes_written());
|
||||||
}
|
}
|
||||||
@ -231,12 +229,12 @@ void DumpSignalInfo(int signal_number, siginfo_t *siginfo) {
|
|||||||
// Dumps information about the stack frame to STDERR.
|
// Dumps information about the stack frame to STDERR.
|
||||||
void DumpStackFrameInfo(const char* prefix, void* pc) {
|
void DumpStackFrameInfo(const char* prefix, void* pc) {
|
||||||
// Get the symbol name.
|
// Get the symbol name.
|
||||||
const char *symbol = "(unknown)";
|
const char* symbol = "(unknown)";
|
||||||
char symbolized[1024]; // Big enough for a sane symbol.
|
char symbolized[1024]; // Big enough for a sane symbol.
|
||||||
// Symbolizes the previous address of pc because pc may be in the
|
// Symbolizes the previous address of pc because pc may be in the
|
||||||
// next function.
|
// next function.
|
||||||
if (Symbolize(reinterpret_cast<char *>(pc) - 1,
|
if (Symbolize(reinterpret_cast<char*>(pc) - 1, symbolized,
|
||||||
symbolized, sizeof(symbolized))) {
|
sizeof(symbolized))) {
|
||||||
symbol = symbolized;
|
symbol = symbolized;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,9 +277,8 @@ static pthread_t* g_entered_thread_id_pointer = nullptr;
|
|||||||
#if defined(GLOG_OS_WINDOWS)
|
#if defined(GLOG_OS_WINDOWS)
|
||||||
void FailureSignalHandler(int signal_number)
|
void FailureSignalHandler(int signal_number)
|
||||||
#else
|
#else
|
||||||
void FailureSignalHandler(int signal_number,
|
void FailureSignalHandler(int signal_number, siginfo_t* signal_info,
|
||||||
siginfo_t *signal_info,
|
void* ucontext)
|
||||||
void *ucontext)
|
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
// First check if we've already entered the function. We use an atomic
|
// First check if we've already entered the function. We use an atomic
|
||||||
@ -324,20 +321,20 @@ void FailureSignalHandler(int signal_number,
|
|||||||
|
|
||||||
#if !defined(GLOG_OS_WINDOWS)
|
#if !defined(GLOG_OS_WINDOWS)
|
||||||
// Get the program counter from ucontext.
|
// Get the program counter from ucontext.
|
||||||
void *pc = GetPC(ucontext);
|
void* pc = GetPC(ucontext);
|
||||||
DumpStackFrameInfo("PC: ", pc);
|
DumpStackFrameInfo("PC: ", pc);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_STACKTRACE
|
#ifdef HAVE_STACKTRACE
|
||||||
// Get the stack traces.
|
// Get the stack traces.
|
||||||
void *stack[32];
|
void* stack[32];
|
||||||
// +1 to exclude this function.
|
// +1 to exclude this function.
|
||||||
const int depth = GetStackTrace(stack, ARRAYSIZE(stack), 1);
|
const int depth = GetStackTrace(stack, ARRAYSIZE(stack), 1);
|
||||||
# ifdef HAVE_SIGACTION
|
# ifdef HAVE_SIGACTION
|
||||||
DumpSignalInfo(signal_number, signal_info);
|
DumpSignalInfo(signal_number, signal_info);
|
||||||
#elif !defined(GLOG_OS_WINDOWS)
|
# elif !defined(GLOG_OS_WINDOWS)
|
||||||
(void)signal_info;
|
(void)signal_info;
|
||||||
# endif
|
# endif
|
||||||
// Dump the stack traces.
|
// Dump the stack traces.
|
||||||
for (int i = 0; i < depth; ++i) {
|
for (int i = 0; i < depth; ++i) {
|
||||||
DumpStackFrameInfo(" ", stack[i]);
|
DumpStackFrameInfo(" ", stack[i]);
|
||||||
@ -400,8 +397,7 @@ void InstallFailureSignalHandler() {
|
|||||||
kFailureSignalHandlerInstalled = true;
|
kFailureSignalHandlerInstalled = true;
|
||||||
#elif defined(GLOG_OS_WINDOWS)
|
#elif defined(GLOG_OS_WINDOWS)
|
||||||
for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
|
for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
|
||||||
CHECK_NE(signal(kFailureSignals[i].number, &FailureSignalHandler),
|
CHECK_NE(signal(kFailureSignals[i].number, &FailureSignalHandler), SIG_ERR);
|
||||||
SIG_ERR);
|
|
||||||
}
|
}
|
||||||
kFailureSignalHandlerInstalled = true;
|
kFailureSignalHandlerInstalled = true;
|
||||||
#endif // HAVE_SIGACTION
|
#endif // HAVE_SIGACTION
|
||||||
|
|||||||
@ -35,7 +35,7 @@
|
|||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
|
||||||
#if defined(HAVE_PTHREAD)
|
#if defined(HAVE_PTHREAD)
|
||||||
# include <pthread.h>
|
# include <pthread.h>
|
||||||
#endif
|
#endif
|
||||||
#include <csignal>
|
#include <csignal>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
@ -45,7 +45,7 @@
|
|||||||
#include "glog/logging.h"
|
#include "glog/logging.h"
|
||||||
|
|
||||||
#ifdef GLOG_USE_GFLAGS
|
#ifdef GLOG_USE_GFLAGS
|
||||||
#include <gflags/gflags.h>
|
# include <gflags/gflags.h>
|
||||||
using namespace GFLAGS_NAMESPACE;
|
using namespace GFLAGS_NAMESPACE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -72,12 +72,12 @@ static void WriteToStdout(const char* data, size_t size) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char** argv) {
|
||||||
#if defined(HAVE_STACKTRACE) && defined(HAVE_SYMBOLIZE)
|
#if defined(HAVE_STACKTRACE) && defined(HAVE_SYMBOLIZE)
|
||||||
InitGoogleLogging(argv[0]);
|
InitGoogleLogging(argv[0]);
|
||||||
#ifdef GLOG_USE_GFLAGS
|
# ifdef GLOG_USE_GFLAGS
|
||||||
ParseCommandLineFlags(&argc, &argv, true);
|
ParseCommandLineFlags(&argc, &argv, true);
|
||||||
#endif
|
# endif
|
||||||
InstallFailureSignalHandler();
|
InstallFailureSignalHandler();
|
||||||
const std::string command = argc > 1 ? argv[1] : "none";
|
const std::string command = argc > 1 ? argv[1] : "none";
|
||||||
if (command == "segv") {
|
if (command == "segv") {
|
||||||
@ -85,26 +85,27 @@ int main(int argc, char **argv) {
|
|||||||
LOG(INFO) << "create the log file";
|
LOG(INFO) << "create the log file";
|
||||||
LOG(INFO) << "a message before segv";
|
LOG(INFO) << "a message before segv";
|
||||||
// We assume 0xDEAD is not writable.
|
// We assume 0xDEAD is not writable.
|
||||||
int *a = (int*)0xDEAD;
|
int* a = (int*)0xDEAD;
|
||||||
*a = 0;
|
*a = 0;
|
||||||
} else if (command == "loop") {
|
} else if (command == "loop") {
|
||||||
fprintf(stderr, "looping\n");
|
fprintf(stderr, "looping\n");
|
||||||
while (true);
|
while (true)
|
||||||
|
;
|
||||||
} else if (command == "die_in_thread") {
|
} else if (command == "die_in_thread") {
|
||||||
#if defined(HAVE_PTHREAD)
|
# if defined(HAVE_PTHREAD)
|
||||||
pthread_t thread;
|
pthread_t thread;
|
||||||
pthread_create(&thread, nullptr, &DieInThread, nullptr);
|
pthread_create(&thread, nullptr, &DieInThread, nullptr);
|
||||||
pthread_join(thread, nullptr);
|
pthread_join(thread, nullptr);
|
||||||
#else
|
# else
|
||||||
fprintf(stderr, "no pthread\n");
|
fprintf(stderr, "no pthread\n");
|
||||||
return 1;
|
return 1;
|
||||||
#endif
|
# endif
|
||||||
} else if (command == "dump_to_stdout") {
|
} else if (command == "dump_to_stdout") {
|
||||||
InstallFailureWriter(WriteToStdout);
|
InstallFailureWriter(WriteToStdout);
|
||||||
abort();
|
abort();
|
||||||
} else if (command == "installed") {
|
} else if (command == "installed") {
|
||||||
fprintf(stderr, "signal handler installed: %s\n",
|
fprintf(stderr, "signal handler installed: %s\n",
|
||||||
IsFailureSignalHandlerInstalled() ? "true" : "false");
|
IsFailureSignalHandlerInstalled() ? "true" : "false");
|
||||||
} else {
|
} else {
|
||||||
// Tell the shell script
|
// Tell the shell script
|
||||||
puts("OK");
|
puts("OK");
|
||||||
|
|||||||
@ -42,7 +42,7 @@ namespace google {
|
|||||||
// If you change this function, also change GetStackFrames below.
|
// If you change this function, also change GetStackFrames below.
|
||||||
int GetStackTrace(void** result, int max_depth, int skip_count) {
|
int GetStackTrace(void** result, int max_depth, int skip_count) {
|
||||||
static const int kStackLength = 64;
|
static const int kStackLength = 64;
|
||||||
void * stack[kStackLength];
|
void* stack[kStackLength];
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
size = backtrace(stack, kStackLength);
|
size = backtrace(stack, kStackLength);
|
||||||
|
|||||||
@ -51,11 +51,11 @@ namespace google {
|
|||||||
// cases, we return 0 to indicate the situation.
|
// cases, we return 0 to indicate the situation.
|
||||||
// We can use the GCC __thread syntax here since libunwind is not supported on
|
// We can use the GCC __thread syntax here since libunwind is not supported on
|
||||||
// Windows.
|
// Windows.
|
||||||
static __thread bool g_tl_entered; // Initialized to false.
|
static __thread bool g_tl_entered; // Initialized to false.
|
||||||
|
|
||||||
// If you change this function, also change GetStackFrames below.
|
// If you change this function, also change GetStackFrames below.
|
||||||
int GetStackTrace(void** result, int max_depth, int skip_count) {
|
int GetStackTrace(void** result, int max_depth, int skip_count) {
|
||||||
void *ip;
|
void* ip;
|
||||||
int n = 0;
|
int n = 0;
|
||||||
unw_cursor_t cursor;
|
unw_cursor_t cursor;
|
||||||
unw_context_t uc;
|
unw_context_t uc;
|
||||||
@ -67,11 +67,11 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
|
|||||||
|
|
||||||
unw_getcontext(&uc);
|
unw_getcontext(&uc);
|
||||||
RAW_CHECK(unw_init_local(&cursor, &uc) >= 0, "unw_init_local failed");
|
RAW_CHECK(unw_init_local(&cursor, &uc) >= 0, "unw_init_local failed");
|
||||||
skip_count++; // Do not include the "GetStackTrace" frame
|
skip_count++; // Do not include the "GetStackTrace" frame
|
||||||
|
|
||||||
while (n < max_depth) {
|
while (n < max_depth) {
|
||||||
int ret =
|
int ret =
|
||||||
unw_get_reg(&cursor, UNW_REG_IP, reinterpret_cast<unw_word_t *>(&ip));
|
unw_get_reg(&cursor, UNW_REG_IP, reinterpret_cast<unw_word_t*>(&ip));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -46,9 +46,9 @@ namespace google {
|
|||||||
// stackframe, or return nullptr if no stackframe can be found. Perform sanity
|
// stackframe, or return nullptr if no stackframe can be found. Perform sanity
|
||||||
// checks (the strictness of which is controlled by the boolean parameter
|
// checks (the strictness of which is controlled by the boolean parameter
|
||||||
// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
|
// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
|
||||||
template<bool STRICT_UNWINDING>
|
template <bool STRICT_UNWINDING>
|
||||||
static void **NextStackFrame(void **old_sp) {
|
static void** NextStackFrame(void** old_sp) {
|
||||||
void **new_sp = static_cast<void **>(*old_sp);
|
void** new_sp = static_cast<void**>(*old_sp);
|
||||||
|
|
||||||
// Check that the transition from frame pointer old_sp to frame
|
// Check that the transition from frame pointer old_sp to frame
|
||||||
// pointer new_sp isn't clearly bogus
|
// pointer new_sp isn't clearly bogus
|
||||||
@ -68,7 +68,7 @@ static void **NextStackFrame(void **old_sp) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((uintptr_t)new_sp & (sizeof(void *) - 1)) return nullptr;
|
if ((uintptr_t)new_sp & (sizeof(void*) - 1)) return nullptr;
|
||||||
return new_sp;
|
return new_sp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,15 +78,15 @@ void StacktracePowerPCDummyFunction() { __asm__ volatile(""); }
|
|||||||
|
|
||||||
// If you change this function, also change GetStackFrames below.
|
// If you change this function, also change GetStackFrames below.
|
||||||
int GetStackTrace(void** result, int max_depth, int skip_count) {
|
int GetStackTrace(void** result, int max_depth, int skip_count) {
|
||||||
void **sp;
|
void** sp;
|
||||||
// Apple OS X uses an old version of gnu as -- both Darwin 7.9.0 (Panther)
|
// Apple OS X uses an old version of gnu as -- both Darwin 7.9.0 (Panther)
|
||||||
// and Darwin 8.8.1 (Tiger) use as 1.38. This means we have to use a
|
// and Darwin 8.8.1 (Tiger) use as 1.38. This means we have to use a
|
||||||
// different asm syntax. I don't know quite the best way to discriminate
|
// different asm syntax. I don't know quite the best way to discriminate
|
||||||
// systems using the old as from the new one; I've gone with __APPLE__.
|
// systems using the old as from the new one; I've gone with __APPLE__.
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
__asm__ volatile ("mr %0,r1" : "=r" (sp));
|
__asm__ volatile("mr %0,r1" : "=r"(sp));
|
||||||
#else
|
#else
|
||||||
__asm__ volatile ("mr %0,1" : "=r" (sp));
|
__asm__ volatile("mr %0,1" : "=r"(sp));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// On PowerPC, the "Link Register" or "Link Record" (LR), is a stack
|
// On PowerPC, the "Link Register" or "Link Record" (LR), is a stack
|
||||||
@ -111,17 +111,18 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
|
|||||||
// linux ppc64), it's in sp[2]. For SYSV (used by linux ppc),
|
// linux ppc64), it's in sp[2]. For SYSV (used by linux ppc),
|
||||||
// it's in sp[1].
|
// it's in sp[1].
|
||||||
#if defined(_CALL_AIX) || defined(_CALL_DARWIN)
|
#if defined(_CALL_AIX) || defined(_CALL_DARWIN)
|
||||||
result[n++] = *(sp+2);
|
result[n++] = *(sp + 2);
|
||||||
#elif defined(_CALL_SYSV)
|
#elif defined(_CALL_SYSV)
|
||||||
result[n++] = *(sp+1);
|
result[n++] = *(sp + 1);
|
||||||
#elif defined(__APPLE__) || ((defined(__linux) || defined(__linux__)) && defined(__PPC64__))
|
#elif defined(__APPLE__) || \
|
||||||
|
((defined(__linux) || defined(__linux__)) && defined(__PPC64__))
|
||||||
// This check is in case the compiler doesn't define _CALL_AIX/etc.
|
// This check is in case the compiler doesn't define _CALL_AIX/etc.
|
||||||
result[n++] = *(sp+2);
|
result[n++] = *(sp + 2);
|
||||||
#elif defined(__linux) || defined(__OpenBSD__)
|
#elif defined(__linux) || defined(__OpenBSD__)
|
||||||
// This check is in case the compiler doesn't define _CALL_SYSV.
|
// This check is in case the compiler doesn't define _CALL_SYSV.
|
||||||
result[n++] = *(sp+1);
|
result[n++] = *(sp + 1);
|
||||||
#else
|
#else
|
||||||
#error Need to specify the PPC ABI for your architecture.
|
# error Need to specify the PPC ABI for your architecture.
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
// Use strict unwinding rules.
|
// Use strict unwinding rules.
|
||||||
|
|||||||
@ -38,7 +38,7 @@
|
|||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
|
||||||
#ifdef HAVE_EXECINFO_BACKTRACE_SYMBOLS
|
#ifdef HAVE_EXECINFO_BACKTRACE_SYMBOLS
|
||||||
# include <execinfo.h>
|
# include <execinfo.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using namespace google;
|
using namespace google;
|
||||||
@ -59,68 +59,74 @@ struct AddressRange {
|
|||||||
// Expected function [start,end] range.
|
// Expected function [start,end] range.
|
||||||
AddressRange expected_range[BACKTRACE_STEPS];
|
AddressRange expected_range[BACKTRACE_STEPS];
|
||||||
|
|
||||||
#if __GNUC__
|
# if __GNUC__
|
||||||
// Using GCC extension: address of a label can be taken with '&&label'.
|
// Using GCC extension: address of a label can be taken with '&&label'.
|
||||||
// Start should be a label somewhere before recursive call, end somewhere
|
// Start should be a label somewhere before recursive call, end somewhere
|
||||||
// after it.
|
// after it.
|
||||||
#define INIT_ADDRESS_RANGE(fn, start_label, end_label, prange) \
|
# define INIT_ADDRESS_RANGE(fn, start_label, end_label, prange) \
|
||||||
do { \
|
do { \
|
||||||
(prange)->start = &&start_label; \
|
(prange)->start = &&start_label; \
|
||||||
(prange)->end = &&end_label; \
|
(prange)->end = &&end_label; \
|
||||||
CHECK_LT((prange)->start, (prange)->end); \
|
CHECK_LT((prange)->start, (prange)->end); \
|
||||||
} while (0)
|
} while (0)
|
||||||
// This macro expands into "unmovable" code (opaque to GCC), and that
|
// This macro expands into "unmovable" code (opaque to GCC), and that
|
||||||
// prevents GCC from moving a_label up or down in the code.
|
// prevents GCC from moving a_label up or down in the code.
|
||||||
// Without it, there is no code following the 'end' label, and GCC
|
// Without it, there is no code following the 'end' label, and GCC
|
||||||
// (4.3.1, 4.4.0) thinks it safe to assign &&end an address that is before
|
// (4.3.1, 4.4.0) thinks it safe to assign &&end an address that is before
|
||||||
// the recursive call.
|
// the recursive call.
|
||||||
#define DECLARE_ADDRESS_LABEL(a_label) \
|
# define DECLARE_ADDRESS_LABEL(a_label) \
|
||||||
a_label: do { __asm__ __volatile__(""); } while (0)
|
a_label: \
|
||||||
|
do { \
|
||||||
|
__asm__ __volatile__(""); \
|
||||||
|
} while (0)
|
||||||
// Gcc 4.4.0 may split function into multiple chunks, and the chunk
|
// Gcc 4.4.0 may split function into multiple chunks, and the chunk
|
||||||
// performing recursive call may end up later in the code then the return
|
// performing recursive call may end up later in the code then the return
|
||||||
// instruction (this actually happens with FDO).
|
// instruction (this actually happens with FDO).
|
||||||
// Adjust function range from __builtin_return_address.
|
// Adjust function range from __builtin_return_address.
|
||||||
#define ADJUST_ADDRESS_RANGE_FROM_RA(prange) \
|
# define ADJUST_ADDRESS_RANGE_FROM_RA(prange) \
|
||||||
do { \
|
do { \
|
||||||
void *ra = __builtin_return_address(0); \
|
void* ra = __builtin_return_address(0); \
|
||||||
CHECK_LT((prange)->start, ra); \
|
CHECK_LT((prange)->start, ra); \
|
||||||
if (ra > (prange)->end) { \
|
if (ra > (prange)->end) { \
|
||||||
printf("Adjusting range from %p..%p to %p..%p\n", \
|
printf("Adjusting range from %p..%p to %p..%p\n", (prange)->start, \
|
||||||
(prange)->start, (prange)->end, \
|
(prange)->end, (prange)->start, ra); \
|
||||||
(prange)->start, ra); \
|
(prange)->end = ra; \
|
||||||
(prange)->end = ra; \
|
} \
|
||||||
} \
|
} while (0)
|
||||||
} while (0)
|
# else
|
||||||
#else
|
|
||||||
// Assume the Check* functions below are not longer than 256 bytes.
|
// Assume the Check* functions below are not longer than 256 bytes.
|
||||||
#define INIT_ADDRESS_RANGE(fn, start_label, end_label, prange) \
|
# define INIT_ADDRESS_RANGE(fn, start_label, end_label, prange) \
|
||||||
do { \
|
do { \
|
||||||
(prange)->start = reinterpret_cast<const void *>(&fn); \
|
(prange)->start = reinterpret_cast<const void*>(&fn); \
|
||||||
(prange)->end = reinterpret_cast<const char *>(&fn) + 256; \
|
(prange)->end = reinterpret_cast<const char*>(&fn) + 256; \
|
||||||
} while (0)
|
} while (0)
|
||||||
#define DECLARE_ADDRESS_LABEL(a_label) do { } while (0)
|
# define DECLARE_ADDRESS_LABEL(a_label) \
|
||||||
#define ADJUST_ADDRESS_RANGE_FROM_RA(prange) do { } while (0)
|
do { \
|
||||||
#endif // __GNUC__
|
} while (0)
|
||||||
|
# define ADJUST_ADDRESS_RANGE_FROM_RA(prange) \
|
||||||
|
do { \
|
||||||
|
} while (0)
|
||||||
|
# endif // __GNUC__
|
||||||
|
|
||||||
//-----------------------------------------------------------------------//
|
//-----------------------------------------------------------------------//
|
||||||
|
|
||||||
static void CheckRetAddrIsInFunction(void *ret_addr, const AddressRange &range)
|
static void CheckRetAddrIsInFunction(void* ret_addr,
|
||||||
{
|
const AddressRange& range) {
|
||||||
CHECK_GE(ret_addr, range.start);
|
CHECK_GE(ret_addr, range.start);
|
||||||
CHECK_LE(ret_addr, range.end);
|
CHECK_LE(ret_addr, range.end);
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------//
|
//-----------------------------------------------------------------------//
|
||||||
|
|
||||||
#if defined(__clang__)
|
# if defined(__clang__)
|
||||||
#pragma clang diagnostic push
|
# pragma clang diagnostic push
|
||||||
#pragma clang diagnostic ignored "-Wgnu-label-as-value"
|
# pragma clang diagnostic ignored "-Wgnu-label-as-value"
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
void ATTRIBUTE_NOINLINE CheckStackTrace(int);
|
void ATTRIBUTE_NOINLINE CheckStackTrace(int);
|
||||||
static void ATTRIBUTE_NOINLINE CheckStackTraceLeaf() {
|
static void ATTRIBUTE_NOINLINE CheckStackTraceLeaf() {
|
||||||
const int STACK_LEN = 10;
|
const int STACK_LEN = 10;
|
||||||
void *stack[STACK_LEN];
|
void* stack[STACK_LEN];
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[1]);
|
ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[1]);
|
||||||
@ -132,8 +138,8 @@ static void ATTRIBUTE_NOINLINE CheckStackTraceLeaf() {
|
|||||||
CHECK_LE(size, STACK_LEN);
|
CHECK_LE(size, STACK_LEN);
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
#ifdef HAVE_EXECINFO_BACKTRACE_SYMBOLS
|
# ifdef HAVE_EXECINFO_BACKTRACE_SYMBOLS
|
||||||
char **strings = backtrace_symbols(stack, size);
|
char** strings = backtrace_symbols(stack, size);
|
||||||
printf("Obtained %d stack frames.\n", size);
|
printf("Obtained %d stack frames.\n", size);
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
printf("%s %p\n", strings[i], stack[i]);
|
printf("%s %p\n", strings[i], stack[i]);
|
||||||
@ -146,11 +152,11 @@ static void ATTRIBUTE_NOINLINE CheckStackTraceLeaf() {
|
|||||||
|
|
||||||
printf("CheckStackTrace() addr: %p\n", p.p2);
|
printf("CheckStackTrace() addr: %p\n", p.p2);
|
||||||
free(strings);
|
free(strings);
|
||||||
#endif
|
# endif
|
||||||
}
|
}
|
||||||
for (int i = 0; i < BACKTRACE_STEPS; i++) {
|
for (int i = 0; i < BACKTRACE_STEPS; i++) {
|
||||||
printf("Backtrace %d: expected: %p..%p actual: %p ... ",
|
printf("Backtrace %d: expected: %p..%p actual: %p ... ", i,
|
||||||
i, expected_range[i].start, expected_range[i].end, stack[i]);
|
expected_range[i].start, expected_range[i].end, stack[i]);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
CheckRetAddrIsInFunction(stack[i], expected_range[i]);
|
CheckRetAddrIsInFunction(stack[i], expected_range[i]);
|
||||||
printf("OK\n");
|
printf("OK\n");
|
||||||
@ -198,7 +204,7 @@ static void ATTRIBUTE_NOINLINE CheckStackTrace1(int i) {
|
|||||||
DECLARE_ADDRESS_LABEL(end);
|
DECLARE_ADDRESS_LABEL(end);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef __GNUC__
|
# ifndef __GNUC__
|
||||||
// On non-GNU environment, we use the address of `CheckStackTrace` to
|
// On non-GNU environment, we use the address of `CheckStackTrace` to
|
||||||
// guess the address range of this function. This guess is wrong for
|
// guess the address range of this function. This guess is wrong for
|
||||||
// non-static function on Windows. This is probably because
|
// non-static function on Windows. This is probably because
|
||||||
@ -206,8 +212,9 @@ static void ATTRIBUTE_NOINLINE CheckStackTrace1(int i) {
|
|||||||
// not the actual address of `CheckStackTrace`.
|
// not the actual address of `CheckStackTrace`.
|
||||||
// See https://github.com/google/glog/issues/421 for the detail.
|
// See https://github.com/google/glog/issues/421 for the detail.
|
||||||
static
|
static
|
||||||
#endif
|
# endif
|
||||||
void ATTRIBUTE_NOINLINE CheckStackTrace(int i) {
|
void ATTRIBUTE_NOINLINE
|
||||||
|
CheckStackTrace(int i) {
|
||||||
INIT_ADDRESS_RANGE(CheckStackTrace, start, end, &expected_range[5]);
|
INIT_ADDRESS_RANGE(CheckStackTrace, start, end, &expected_range[5]);
|
||||||
DECLARE_ADDRESS_LABEL(start);
|
DECLARE_ADDRESS_LABEL(start);
|
||||||
for (int j = i; j >= 0; j--) {
|
for (int j = i; j >= 0; j--) {
|
||||||
@ -216,13 +223,13 @@ void ATTRIBUTE_NOINLINE CheckStackTrace(int i) {
|
|||||||
DECLARE_ADDRESS_LABEL(end);
|
DECLARE_ADDRESS_LABEL(end);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__clang__)
|
# if defined(__clang__)
|
||||||
#pragma clang diagnostic pop
|
# pragma clang diagnostic pop
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
//-----------------------------------------------------------------------//
|
//-----------------------------------------------------------------------//
|
||||||
|
|
||||||
int main(int, char ** argv) {
|
int main(int, char** argv) {
|
||||||
FLAGS_logtostderr = true;
|
FLAGS_logtostderr = true;
|
||||||
InitGoogleLogging(argv[0]);
|
InitGoogleLogging(argv[0]);
|
||||||
|
|
||||||
@ -235,12 +242,12 @@ int main(int, char ** argv) {
|
|||||||
#else
|
#else
|
||||||
int main() {
|
int main() {
|
||||||
|
|
||||||
#ifdef GLOG_BAZEL_BUILD
|
# ifdef GLOG_BAZEL_BUILD
|
||||||
printf("HAVE_STACKTRACE is expected to be defined in Bazel tests\n");
|
printf("HAVE_STACKTRACE is expected to be defined in Bazel tests\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
#endif // GLOG_BAZEL_BUILD
|
# endif // GLOG_BAZEL_BUILD
|
||||||
|
|
||||||
printf("PASS (no stacktrace support)\n");
|
printf("PASS (no stacktrace support)\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif // HAVE_STACKTRACE
|
#endif // HAVE_STACKTRACE
|
||||||
|
|||||||
@ -38,41 +38,41 @@
|
|||||||
namespace google {
|
namespace google {
|
||||||
|
|
||||||
struct trace_arg_t {
|
struct trace_arg_t {
|
||||||
void **result;
|
void** result;
|
||||||
int max_depth;
|
int max_depth;
|
||||||
int skip_count;
|
int skip_count;
|
||||||
int count;
|
int count;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Workaround for the malloc() in _Unwind_Backtrace() issue.
|
// Workaround for the malloc() in _Unwind_Backtrace() issue.
|
||||||
static _Unwind_Reason_Code nop_backtrace(struct _Unwind_Context */*uc*/, void */*opq*/) {
|
static _Unwind_Reason_Code nop_backtrace(struct _Unwind_Context* /*uc*/,
|
||||||
|
void* /*opq*/) {
|
||||||
return _URC_NO_REASON;
|
return _URC_NO_REASON;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// This code is not considered ready to run until
|
// This code is not considered ready to run until
|
||||||
// static initializers run so that we are guaranteed
|
// static initializers run so that we are guaranteed
|
||||||
// that any malloc-related initialization is done.
|
// that any malloc-related initialization is done.
|
||||||
static bool ready_to_run = false;
|
static bool ready_to_run = false;
|
||||||
class StackTraceInit {
|
class StackTraceInit {
|
||||||
public:
|
public:
|
||||||
StackTraceInit() {
|
StackTraceInit() {
|
||||||
// Extra call to force initialization
|
// Extra call to force initialization
|
||||||
_Unwind_Backtrace(nop_backtrace, nullptr);
|
_Unwind_Backtrace(nop_backtrace, nullptr);
|
||||||
ready_to_run = true;
|
ready_to_run = true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static StackTraceInit module_initializer; // Force initialization
|
static StackTraceInit module_initializer; // Force initialization
|
||||||
|
|
||||||
static _Unwind_Reason_Code GetOneFrame(struct _Unwind_Context *uc, void *opq) {
|
static _Unwind_Reason_Code GetOneFrame(struct _Unwind_Context* uc, void* opq) {
|
||||||
auto *targ = static_cast<trace_arg_t *>(opq);
|
auto* targ = static_cast<trace_arg_t*>(opq);
|
||||||
|
|
||||||
if (targ->skip_count > 0) {
|
if (targ->skip_count > 0) {
|
||||||
targ->skip_count--;
|
targ->skip_count--;
|
||||||
} else {
|
} else {
|
||||||
targ->result[targ->count++] = reinterpret_cast<void *>(_Unwind_GetIP(uc));
|
targ->result[targ->count++] = reinterpret_cast<void*>(_Unwind_GetIP(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targ->count == targ->max_depth) {
|
if (targ->count == targ->max_depth) {
|
||||||
return _URC_END_OF_STACK;
|
return _URC_END_OF_STACK;
|
||||||
@ -89,7 +89,7 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
|
|||||||
|
|
||||||
trace_arg_t targ;
|
trace_arg_t targ;
|
||||||
|
|
||||||
skip_count += 1; // Do not include the "GetStackTrace" frame
|
skip_count += 1; // Do not include the "GetStackTrace" frame
|
||||||
|
|
||||||
targ.result = result;
|
targ.result = result;
|
||||||
targ.max_depth = max_depth;
|
targ.max_depth = max_depth;
|
||||||
|
|||||||
@ -31,10 +31,11 @@
|
|||||||
//
|
//
|
||||||
// Windows implementation - just use CaptureStackBackTrace
|
// Windows implementation - just use CaptureStackBackTrace
|
||||||
|
|
||||||
|
#include <dbghelp.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "port.h"
|
#include "port.h"
|
||||||
#include "stacktrace.h"
|
#include "stacktrace.h"
|
||||||
#include <dbghelp.h>
|
|
||||||
|
|
||||||
namespace google {
|
namespace google {
|
||||||
|
|
||||||
|
|||||||
@ -31,11 +31,11 @@
|
|||||||
|
|
||||||
#include <cstdint> // for uintptr_t
|
#include <cstdint> // for uintptr_t
|
||||||
|
|
||||||
#include "utilities.h" // for OS_* macros
|
#include "utilities.h" // for OS_* macros
|
||||||
|
|
||||||
#if !defined(GLOG_OS_WINDOWS)
|
#if !defined(GLOG_OS_WINDOWS)
|
||||||
#include <unistd.h>
|
# include <sys/mman.h>
|
||||||
#include <sys/mman.h>
|
# include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <cstdio> // for nullptr
|
#include <cstdio> // for nullptr
|
||||||
@ -48,9 +48,9 @@ namespace google {
|
|||||||
// stackframe, or return nullptr if no stackframe can be found. Perform sanity
|
// stackframe, or return nullptr if no stackframe can be found. Perform sanity
|
||||||
// checks (the strictness of which is controlled by the boolean parameter
|
// checks (the strictness of which is controlled by the boolean parameter
|
||||||
// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
|
// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
|
||||||
template<bool STRICT_UNWINDING>
|
template <bool STRICT_UNWINDING>
|
||||||
static void **NextStackFrame(void **old_sp) {
|
static void** NextStackFrame(void** old_sp) {
|
||||||
void **new_sp = static_cast<void **>(*old_sp);
|
void** new_sp = static_cast<void**>(*old_sp);
|
||||||
|
|
||||||
// Check that the transition from frame pointer old_sp to frame
|
// Check that the transition from frame pointer old_sp to frame
|
||||||
// pointer new_sp isn't clearly bogus
|
// pointer new_sp isn't clearly bogus
|
||||||
@ -75,7 +75,7 @@ static void **NextStackFrame(void **old_sp) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (reinterpret_cast<uintptr_t>(new_sp) & (sizeof(void *) - 1)) {
|
if (reinterpret_cast<uintptr_t>(new_sp) & (sizeof(void*) - 1)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
#ifdef __i386__
|
#ifdef __i386__
|
||||||
@ -92,9 +92,9 @@ static void **NextStackFrame(void **old_sp) {
|
|||||||
// Note: NextStackFrame<false>() is only called while the program
|
// Note: NextStackFrame<false>() is only called while the program
|
||||||
// is already on its last leg, so it's ok to be slow here.
|
// is already on its last leg, so it's ok to be slow here.
|
||||||
static int page_size = getpagesize();
|
static int page_size = getpagesize();
|
||||||
void *new_sp_aligned =
|
void* new_sp_aligned =
|
||||||
reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(new_sp) &
|
reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(new_sp) &
|
||||||
static_cast<uintptr_t>(~(page_size - 1)));
|
static_cast<uintptr_t>(~(page_size - 1)));
|
||||||
if (msync(new_sp_aligned, static_cast<size_t>(page_size), MS_ASYNC) == -1) {
|
if (msync(new_sp_aligned, static_cast<size_t>(page_size), MS_ASYNC) == -1) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -105,12 +105,12 @@ static void **NextStackFrame(void **old_sp) {
|
|||||||
|
|
||||||
// If you change this function, also change GetStackFrames below.
|
// If you change this function, also change GetStackFrames below.
|
||||||
int GetStackTrace(void** result, int max_depth, int skip_count) {
|
int GetStackTrace(void** result, int max_depth, int skip_count) {
|
||||||
void **sp;
|
void** sp;
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
#if __GNUC__ * 100 + __GNUC_MINOR__ >= 402
|
# if __GNUC__ * 100 + __GNUC_MINOR__ >= 402
|
||||||
#define USE_BUILTIN_FRAME_ADDRESS
|
# define USE_BUILTIN_FRAME_ADDRESS
|
||||||
#endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_BUILTIN_FRAME_ADDRESS
|
#ifdef USE_BUILTIN_FRAME_ADDRESS
|
||||||
@ -121,7 +121,7 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
|
|||||||
// sp[1] caller address
|
// sp[1] caller address
|
||||||
// sp[2] first argument
|
// sp[2] first argument
|
||||||
// ...
|
// ...
|
||||||
sp = (void **)&result - 2;
|
sp = (void**)&result - 2;
|
||||||
#elif defined(__x86_64__)
|
#elif defined(__x86_64__)
|
||||||
// __builtin_frame_address(0) can return the wrong address on gcc-4.1.0-k8
|
// __builtin_frame_address(0) can return the wrong address on gcc-4.1.0-k8
|
||||||
unsigned long rbp;
|
unsigned long rbp;
|
||||||
@ -132,10 +132,10 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
|
|||||||
// would be (before this __asm__ instruction) to call Noop() defined as
|
// would be (before this __asm__ instruction) to call Noop() defined as
|
||||||
// static void Noop() __attribute__ ((noinline)); // prevent inlining
|
// static void Noop() __attribute__ ((noinline)); // prevent inlining
|
||||||
// static void Noop() { asm(""); } // prevent optimizing-away
|
// static void Noop() { asm(""); } // prevent optimizing-away
|
||||||
__asm__ volatile ("mov %%rbp, %0" : "=r" (rbp));
|
__asm__ volatile("mov %%rbp, %0" : "=r"(rbp));
|
||||||
// Arguments are passed in registers on x86-64, so we can't just
|
// Arguments are passed in registers on x86-64, so we can't just
|
||||||
// offset from &result
|
// offset from &result
|
||||||
sp = (void **) rbp;
|
sp = (void**)rbp;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int n = 0;
|
int n = 0;
|
||||||
@ -148,7 +148,7 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
|
|||||||
if (skip_count > 0) {
|
if (skip_count > 0) {
|
||||||
skip_count--;
|
skip_count--;
|
||||||
} else {
|
} else {
|
||||||
result[n++] = *(sp+1);
|
result[n++] = *(sp + 1);
|
||||||
}
|
}
|
||||||
// Use strict unwinding rules.
|
// Use strict unwinding rules.
|
||||||
sp = NextStackFrame<true>(sp);
|
sp = NextStackFrame<true>(sp);
|
||||||
|
|||||||
@ -62,14 +62,14 @@ static void TestSTLLogging() {
|
|||||||
|
|
||||||
{
|
{
|
||||||
// Test a sorted pair associative container.
|
// Test a sorted pair associative container.
|
||||||
map< int, string > m;
|
map<int, string> m;
|
||||||
m[20] = "twenty";
|
m[20] = "twenty";
|
||||||
m[10] = "ten";
|
m[10] = "ten";
|
||||||
m[30] = "thirty";
|
m[30] = "thirty";
|
||||||
ostringstream ss;
|
ostringstream ss;
|
||||||
ss << m;
|
ss << m;
|
||||||
EXPECT_EQ(ss.str(), "(10, ten) (20, twenty) (30, thirty)");
|
EXPECT_EQ(ss.str(), "(10, ten) (20, twenty) (30, thirty)");
|
||||||
map< int, string > copied_m(m);
|
map<int, string> copied_m(m);
|
||||||
CHECK_EQ(m, copied_m); // This must compile.
|
CHECK_EQ(m, copied_m); // This must compile.
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,14 +95,14 @@ static void TestSTLLogging() {
|
|||||||
{
|
{
|
||||||
// Test a sorted pair associative container.
|
// Test a sorted pair associative container.
|
||||||
// Use a non-default comparison functor.
|
// Use a non-default comparison functor.
|
||||||
map<int, string, greater<> > m;
|
map<int, string, greater<>> m;
|
||||||
m[20] = "twenty";
|
m[20] = "twenty";
|
||||||
m[10] = "ten";
|
m[10] = "ten";
|
||||||
m[30] = "thirty";
|
m[30] = "thirty";
|
||||||
ostringstream ss;
|
ostringstream ss;
|
||||||
ss << m;
|
ss << m;
|
||||||
EXPECT_EQ(ss.str(), "(30, thirty) (20, twenty) (10, ten)");
|
EXPECT_EQ(ss.str(), "(30, thirty) (20, twenty) (10, ten)");
|
||||||
map<int, string, greater<> > copied_m(m);
|
map<int, string, greater<>> copied_m(m);
|
||||||
CHECK_EQ(m, copied_m); // This must compile.
|
CHECK_EQ(m, copied_m); // This must compile.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -57,13 +57,13 @@ int CheckNoReturn(bool b) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct A {};
|
struct A {};
|
||||||
std::ostream &operator<<(std::ostream &str, const A &) { return str; }
|
std::ostream& operator<<(std::ostream& str, const A&) { return str; }
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
void handle_abort(int /*code*/) { std::exit(EXIT_FAILURE); }
|
void handle_abort(int /*code*/) { std::exit(EXIT_FAILURE); }
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
int main(int, char *argv[]) {
|
int main(int, char* argv[]) {
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
// Avoid presenting an interactive dialog that will cause the test to time
|
// Avoid presenting an interactive dialog that will cause the test to time
|
||||||
// out.
|
// out.
|
||||||
|
|||||||
280
src/symbolize.cc
280
src/symbolize.cc
@ -49,20 +49,19 @@
|
|||||||
// macro to add platform specific defines (e.g. GLOG_OS_OPENBSD).
|
// macro to add platform specific defines (e.g. GLOG_OS_OPENBSD).
|
||||||
|
|
||||||
#ifdef GLOG_BUILD_CONFIG_INCLUDE
|
#ifdef GLOG_BUILD_CONFIG_INCLUDE
|
||||||
#include GLOG_BUILD_CONFIG_INCLUDE
|
# include GLOG_BUILD_CONFIG_INCLUDE
|
||||||
#endif // GLOG_BUILD_CONFIG_INCLUDE
|
#endif // GLOG_BUILD_CONFIG_INCLUDE
|
||||||
|
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
|
||||||
#if defined(HAVE_SYMBOLIZE)
|
#if defined(HAVE_SYMBOLIZE)
|
||||||
|
|
||||||
#include <cstring>
|
# include <algorithm>
|
||||||
|
# include <cstring>
|
||||||
|
# include <limits>
|
||||||
|
|
||||||
#include <algorithm>
|
# include "demangle.h"
|
||||||
#include <limits>
|
# include "symbolize.h"
|
||||||
|
|
||||||
#include "symbolize.h"
|
|
||||||
#include "demangle.h"
|
|
||||||
|
|
||||||
namespace google {
|
namespace google {
|
||||||
|
|
||||||
@ -76,7 +75,7 @@ static int AssertFail() {
|
|||||||
return 0; // Should not reach.
|
return 0; // Should not reach.
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SAFE_ASSERT(expr) ((expr) ? 0 : AssertFail())
|
# define SAFE_ASSERT(expr) ((expr) ? 0 : AssertFail())
|
||||||
|
|
||||||
static SymbolizeCallback g_symbolize_callback = nullptr;
|
static SymbolizeCallback g_symbolize_callback = nullptr;
|
||||||
void InstallSymbolizeCallback(SymbolizeCallback callback) {
|
void InstallSymbolizeCallback(SymbolizeCallback callback) {
|
||||||
@ -94,7 +93,7 @@ void InstallSymbolizeOpenObjectFileCallback(
|
|||||||
// where the input symbol is demangled in-place.
|
// where the input symbol is demangled in-place.
|
||||||
// To keep stack consumption low, we would like this function to not
|
// To keep stack consumption low, we would like this function to not
|
||||||
// get inlined.
|
// get inlined.
|
||||||
static ATTRIBUTE_NOINLINE void DemangleInplace(char *out, size_t out_size) {
|
static ATTRIBUTE_NOINLINE void DemangleInplace(char* out, size_t out_size) {
|
||||||
char demangled[256]; // Big enough for sane demangled symbols.
|
char demangled[256]; // Big enough for sane demangled symbols.
|
||||||
if (Demangle(out, demangled, sizeof(demangled))) {
|
if (Demangle(out, demangled, sizeof(demangled))) {
|
||||||
// Demangling succeeded. Copy to out if the space allows.
|
// Demangling succeeded. Copy to out if the space allows.
|
||||||
@ -108,35 +107,37 @@ static ATTRIBUTE_NOINLINE void DemangleInplace(char *out, size_t out_size) {
|
|||||||
|
|
||||||
} // namespace google
|
} // namespace google
|
||||||
|
|
||||||
#if defined(__ELF__)
|
# if defined(__ELF__)
|
||||||
|
|
||||||
#if defined(HAVE_DLFCN_H)
|
# if defined(HAVE_DLFCN_H)
|
||||||
#include <dlfcn.h>
|
# include <dlfcn.h>
|
||||||
#endif
|
# endif
|
||||||
#if defined(GLOG_OS_OPENBSD)
|
# if defined(GLOG_OS_OPENBSD)
|
||||||
#include <sys/exec_elf.h>
|
# include <sys/exec_elf.h>
|
||||||
#else
|
# else
|
||||||
#include <elf.h>
|
# include <elf.h>
|
||||||
#endif
|
# endif
|
||||||
#include <fcntl.h>
|
# include <fcntl.h>
|
||||||
#include <sys/stat.h>
|
# include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
# include <sys/types.h>
|
||||||
#include <unistd.h>
|
# include <unistd.h>
|
||||||
|
|
||||||
#include <cerrno>
|
# include <cerrno>
|
||||||
#include <climits>
|
# include <climits>
|
||||||
#include <cstddef>
|
# include <cstddef>
|
||||||
#include <cstdint>
|
# include <cstdint>
|
||||||
#include <cstdio>
|
# include <cstdio>
|
||||||
#include <cstdlib>
|
# include <cstdlib>
|
||||||
#include <cstring>
|
# include <cstring>
|
||||||
|
|
||||||
#include "config.h"
|
# include "config.h"
|
||||||
#include "glog/raw_logging.h"
|
# include "glog/raw_logging.h"
|
||||||
#include "symbolize.h"
|
# include "symbolize.h"
|
||||||
|
|
||||||
// Re-runs fn until it doesn't cause EINTR.
|
// Re-runs fn until it doesn't cause EINTR.
|
||||||
#define NO_INTR(fn) do {} while ((fn) < 0 && errno == EINTR)
|
# define NO_INTR(fn) \
|
||||||
|
do { \
|
||||||
|
} while ((fn) < 0 && errno == EINTR)
|
||||||
|
|
||||||
namespace google {
|
namespace google {
|
||||||
|
|
||||||
@ -144,11 +145,12 @@ namespace google {
|
|||||||
// descriptor "fd" into the buffer starting at "buf" while handling short reads
|
// descriptor "fd" into the buffer starting at "buf" while handling short reads
|
||||||
// and EINTR. On success, return the number of bytes read. Otherwise, return
|
// and EINTR. On success, return the number of bytes read. Otherwise, return
|
||||||
// -1.
|
// -1.
|
||||||
static ssize_t ReadFromOffset(const int fd, void *buf, const size_t count,
|
static ssize_t ReadFromOffset(const int fd, void* buf, const size_t count,
|
||||||
const size_t offset) {
|
const size_t offset) {
|
||||||
SAFE_ASSERT(fd >= 0);
|
SAFE_ASSERT(fd >= 0);
|
||||||
SAFE_ASSERT(count <= static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
|
SAFE_ASSERT(count <=
|
||||||
char *buf0 = reinterpret_cast<char *>(buf);
|
static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
|
||||||
|
char* buf0 = reinterpret_cast<char*>(buf);
|
||||||
size_t num_bytes = 0;
|
size_t num_bytes = 0;
|
||||||
while (num_bytes < count) {
|
while (num_bytes < count) {
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
@ -170,8 +172,8 @@ static ssize_t ReadFromOffset(const int fd, void *buf, const size_t count,
|
|||||||
// pointed by "fd" into the buffer starting at "buf" while handling
|
// pointed by "fd" into the buffer starting at "buf" while handling
|
||||||
// short reads and EINTR. On success, return true. Otherwise, return
|
// short reads and EINTR. On success, return true. Otherwise, return
|
||||||
// false.
|
// false.
|
||||||
static bool ReadFromOffsetExact(const int fd, void *buf,
|
static bool ReadFromOffsetExact(const int fd, void* buf, const size_t count,
|
||||||
const size_t count, const size_t offset) {
|
const size_t offset) {
|
||||||
ssize_t len = ReadFromOffset(fd, buf, count, offset);
|
ssize_t len = ReadFromOffset(fd, buf, count, offset);
|
||||||
return static_cast<size_t>(len) == count;
|
return static_cast<size_t>(len) == count;
|
||||||
}
|
}
|
||||||
@ -193,9 +195,11 @@ static int FileGetElfType(const int fd) {
|
|||||||
// and return true. Otherwise, return false.
|
// and return true. Otherwise, return false.
|
||||||
// To keep stack consumption low, we would like this function to not get
|
// To keep stack consumption low, we would like this function to not get
|
||||||
// inlined.
|
// inlined.
|
||||||
static ATTRIBUTE_NOINLINE bool
|
static ATTRIBUTE_NOINLINE bool GetSectionHeaderByType(const int fd,
|
||||||
GetSectionHeaderByType(const int fd, ElfW(Half) sh_num, const size_t sh_offset,
|
ElfW(Half) sh_num,
|
||||||
ElfW(Word) type, ElfW(Shdr) *out) {
|
const size_t sh_offset,
|
||||||
|
ElfW(Word) type,
|
||||||
|
ElfW(Shdr) * out) {
|
||||||
// Read at most 16 section headers at a time to save read calls.
|
// Read at most 16 section headers at a time to save read calls.
|
||||||
ElfW(Shdr) buf[16];
|
ElfW(Shdr) buf[16];
|
||||||
for (size_t i = 0; i < sh_num;) {
|
for (size_t i = 0; i < sh_num;) {
|
||||||
@ -226,8 +230,8 @@ GetSectionHeaderByType(const int fd, ElfW(Half) sh_num, const size_t sh_offset,
|
|||||||
const int kMaxSectionNameLen = 64;
|
const int kMaxSectionNameLen = 64;
|
||||||
|
|
||||||
// name_len should include terminating '\0'.
|
// name_len should include terminating '\0'.
|
||||||
bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
|
bool GetSectionHeaderByName(int fd, const char* name, size_t name_len,
|
||||||
ElfW(Shdr) *out) {
|
ElfW(Shdr) * out) {
|
||||||
ElfW(Ehdr) elf_header;
|
ElfW(Ehdr) elf_header;
|
||||||
if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
|
if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
|
||||||
return false;
|
return false;
|
||||||
@ -242,8 +246,8 @@ bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < elf_header.e_shnum; ++i) {
|
for (size_t i = 0; i < elf_header.e_shnum; ++i) {
|
||||||
size_t section_header_offset = (elf_header.e_shoff +
|
size_t section_header_offset =
|
||||||
elf_header.e_shentsize * i);
|
(elf_header.e_shoff + elf_header.e_shentsize * i);
|
||||||
if (!ReadFromOffsetExact(fd, out, sizeof(*out), section_header_offset)) {
|
if (!ReadFromOffsetExact(fd, out, sizeof(*out), section_header_offset)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -277,10 +281,11 @@ bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
|
|||||||
// to out. Otherwise, return false.
|
// to out. Otherwise, return false.
|
||||||
// To keep stack consumption low, we would like this function to not get
|
// To keep stack consumption low, we would like this function to not get
|
||||||
// inlined.
|
// inlined.
|
||||||
static ATTRIBUTE_NOINLINE bool
|
static ATTRIBUTE_NOINLINE bool FindSymbol(uint64_t pc, const int fd, char* out,
|
||||||
FindSymbol(uint64_t pc, const int fd, char *out, size_t out_size,
|
size_t out_size,
|
||||||
uint64_t symbol_offset, const ElfW(Shdr) *strtab,
|
uint64_t symbol_offset,
|
||||||
const ElfW(Shdr) *symtab) {
|
const ElfW(Shdr) * strtab,
|
||||||
|
const ElfW(Shdr) * symtab) {
|
||||||
if (symtab == nullptr) {
|
if (symtab == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -291,11 +296,11 @@ FindSymbol(uint64_t pc, const int fd, char *out, size_t out_size,
|
|||||||
// If we are reading Elf64_Sym's, we want to limit this array to
|
// If we are reading Elf64_Sym's, we want to limit this array to
|
||||||
// 32 elements (to keep stack consumption low), otherwise we can
|
// 32 elements (to keep stack consumption low), otherwise we can
|
||||||
// have a 64 element Elf32_Sym array.
|
// have a 64 element Elf32_Sym array.
|
||||||
#if defined(__WORDSIZE) && __WORDSIZE == 64
|
# if defined(__WORDSIZE) && __WORDSIZE == 64
|
||||||
const size_t NUM_SYMBOLS = 32U;
|
const size_t NUM_SYMBOLS = 32U;
|
||||||
#else
|
# else
|
||||||
const size_t NUM_SYMBOLS = 64U;
|
const size_t NUM_SYMBOLS = 64U;
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
// Read at most NUM_SYMBOLS symbols at once to save read() calls.
|
// Read at most NUM_SYMBOLS symbols at once to save read() calls.
|
||||||
ElfW(Sym) buf[NUM_SYMBOLS];
|
ElfW(Sym) buf[NUM_SYMBOLS];
|
||||||
@ -331,11 +336,8 @@ FindSymbol(uint64_t pc, const int fd, char *out, size_t out_size,
|
|||||||
// both regular and dynamic symbol tables if necessary. On success,
|
// both regular and dynamic symbol tables if necessary. On success,
|
||||||
// write the symbol name to "out" and return true. Otherwise, return
|
// write the symbol name to "out" and return true. Otherwise, return
|
||||||
// false.
|
// false.
|
||||||
static bool GetSymbolFromObjectFile(const int fd,
|
static bool GetSymbolFromObjectFile(const int fd, uint64_t pc, char* out,
|
||||||
uint64_t pc,
|
size_t out_size, uint64_t base_address) {
|
||||||
char* out,
|
|
||||||
size_t out_size,
|
|
||||||
uint64_t base_address) {
|
|
||||||
// Read the ELF header.
|
// Read the ELF header.
|
||||||
ElfW(Ehdr) elf_header;
|
ElfW(Ehdr) elf_header;
|
||||||
if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
|
if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
|
||||||
@ -347,8 +349,9 @@ static bool GetSymbolFromObjectFile(const int fd,
|
|||||||
// Consult a regular symbol table first.
|
// Consult a regular symbol table first.
|
||||||
if (GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
|
if (GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
|
||||||
SHT_SYMTAB, &symtab)) {
|
SHT_SYMTAB, &symtab)) {
|
||||||
if (!ReadFromOffsetExact(fd, &strtab, sizeof(strtab), elf_header.e_shoff +
|
if (!ReadFromOffsetExact(
|
||||||
symtab.sh_link * sizeof(symtab))) {
|
fd, &strtab, sizeof(strtab),
|
||||||
|
elf_header.e_shoff + symtab.sh_link * sizeof(symtab))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (FindSymbol(pc, fd, out, out_size, base_address, &strtab, &symtab)) {
|
if (FindSymbol(pc, fd, out, out_size, base_address, &strtab, &symtab)) {
|
||||||
@ -359,8 +362,9 @@ static bool GetSymbolFromObjectFile(const int fd,
|
|||||||
// If the symbol is not found, then consult a dynamic symbol table.
|
// If the symbol is not found, then consult a dynamic symbol table.
|
||||||
if (GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
|
if (GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
|
||||||
SHT_DYNSYM, &symtab)) {
|
SHT_DYNSYM, &symtab)) {
|
||||||
if (!ReadFromOffsetExact(fd, &strtab, sizeof(strtab), elf_header.e_shoff +
|
if (!ReadFromOffsetExact(
|
||||||
symtab.sh_link * sizeof(symtab))) {
|
fd, &strtab, sizeof(strtab),
|
||||||
|
elf_header.e_shoff + symtab.sh_link * sizeof(symtab))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (FindSymbol(pc, fd, out, out_size, base_address, &strtab, &symtab)) {
|
if (FindSymbol(pc, fd, out, out_size, base_address, &strtab, &symtab)) {
|
||||||
@ -385,8 +389,8 @@ struct FileDescriptor {
|
|||||||
int get() { return fd_; }
|
int get() { return fd_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FileDescriptor(const FileDescriptor &) = delete;
|
FileDescriptor(const FileDescriptor&) = delete;
|
||||||
void operator=(const FileDescriptor &) = delete;
|
void operator=(const FileDescriptor&) = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Helper class for reading lines from file.
|
// Helper class for reading lines from file.
|
||||||
@ -396,7 +400,7 @@ struct FileDescriptor {
|
|||||||
// and std::snprintf().
|
// and std::snprintf().
|
||||||
class LineReader {
|
class LineReader {
|
||||||
public:
|
public:
|
||||||
explicit LineReader(int fd, char *buf, size_t buf_len, size_t offset)
|
explicit LineReader(int fd, char* buf, size_t buf_len, size_t offset)
|
||||||
: fd_(fd),
|
: fd_(fd),
|
||||||
buf_(buf),
|
buf_(buf),
|
||||||
buf_len_(buf_len),
|
buf_len_(buf_len),
|
||||||
@ -410,7 +414,7 @@ class LineReader {
|
|||||||
//
|
//
|
||||||
// Note: if the last line doesn't end with '\n', the line will be
|
// Note: if the last line doesn't end with '\n', the line will be
|
||||||
// dropped. It's an intentional behavior to make the code simple.
|
// dropped. It's an intentional behavior to make the code simple.
|
||||||
bool ReadLine(const char **bol, const char **eol) {
|
bool ReadLine(const char** bol, const char** eol) {
|
||||||
if (BufferIsEmpty()) { // First time.
|
if (BufferIsEmpty()) { // First time.
|
||||||
const ssize_t num_bytes = ReadFromOffset(fd_, buf_, buf_len_, offset_);
|
const ssize_t num_bytes = ReadFromOffset(fd_, buf_, buf_len_, offset_);
|
||||||
if (num_bytes <= 0) { // EOF or error.
|
if (num_bytes <= 0) { // EOF or error.
|
||||||
@ -420,14 +424,14 @@ class LineReader {
|
|||||||
eod_ = buf_ + num_bytes;
|
eod_ = buf_ + num_bytes;
|
||||||
bol_ = buf_;
|
bol_ = buf_;
|
||||||
} else {
|
} else {
|
||||||
bol_ = eol_ + 1; // Advance to the next line in the buffer.
|
bol_ = eol_ + 1; // Advance to the next line in the buffer.
|
||||||
SAFE_ASSERT(bol_ <= eod_); // "bol_" can point to "eod_".
|
SAFE_ASSERT(bol_ <= eod_); // "bol_" can point to "eod_".
|
||||||
if (!HasCompleteLine()) {
|
if (!HasCompleteLine()) {
|
||||||
const auto incomplete_line_length = static_cast<size_t>(eod_ - bol_);
|
const auto incomplete_line_length = static_cast<size_t>(eod_ - bol_);
|
||||||
// Move the trailing incomplete line to the beginning.
|
// Move the trailing incomplete line to the beginning.
|
||||||
memmove(buf_, bol_, incomplete_line_length);
|
memmove(buf_, bol_, incomplete_line_length);
|
||||||
// Read text from file and append it.
|
// Read text from file and append it.
|
||||||
char * const append_pos = buf_ + incomplete_line_length;
|
char* const append_pos = buf_ + incomplete_line_length;
|
||||||
const size_t capacity_left = buf_len_ - incomplete_line_length;
|
const size_t capacity_left = buf_len_ - incomplete_line_length;
|
||||||
const ssize_t num_bytes =
|
const ssize_t num_bytes =
|
||||||
ReadFromOffset(fd_, append_pos, capacity_left, offset_);
|
ReadFromOffset(fd_, append_pos, capacity_left, offset_);
|
||||||
@ -451,57 +455,53 @@ class LineReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Beginning of line.
|
// Beginning of line.
|
||||||
const char *bol() {
|
const char* bol() { return bol_; }
|
||||||
return bol_;
|
|
||||||
}
|
|
||||||
|
|
||||||
// End of line.
|
// End of line.
|
||||||
const char *eol() {
|
const char* eol() { return eol_; }
|
||||||
return eol_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
LineReader(const LineReader &) = delete;
|
LineReader(const LineReader&) = delete;
|
||||||
void operator=(const LineReader &) = delete;
|
void operator=(const LineReader&) = delete;
|
||||||
|
|
||||||
char *FindLineFeed() {
|
char* FindLineFeed() {
|
||||||
return reinterpret_cast<char *>(memchr(bol_, '\n', static_cast<size_t>(eod_ - bol_)));
|
return reinterpret_cast<char*>(
|
||||||
|
memchr(bol_, '\n', static_cast<size_t>(eod_ - bol_)));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BufferIsEmpty() {
|
bool BufferIsEmpty() { return buf_ == eod_; }
|
||||||
return buf_ == eod_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HasCompleteLine() {
|
bool HasCompleteLine() {
|
||||||
return !BufferIsEmpty() && FindLineFeed() != nullptr;
|
return !BufferIsEmpty() && FindLineFeed() != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int fd_;
|
const int fd_;
|
||||||
char * const buf_;
|
char* const buf_;
|
||||||
const size_t buf_len_;
|
const size_t buf_len_;
|
||||||
size_t offset_;
|
size_t offset_;
|
||||||
char *bol_;
|
char* bol_;
|
||||||
char *eol_;
|
char* eol_;
|
||||||
const char *eod_; // End of data in "buf_".
|
const char* eod_; // End of data in "buf_".
|
||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
// Place the hex number read from "start" into "*hex". The pointer to
|
// Place the hex number read from "start" into "*hex". The pointer to
|
||||||
// the first non-hex character or "end" is returned.
|
// the first non-hex character or "end" is returned.
|
||||||
static char *GetHex(const char *start, const char *end, uint64_t *hex) {
|
static char* GetHex(const char* start, const char* end, uint64_t* hex) {
|
||||||
*hex = 0;
|
*hex = 0;
|
||||||
const char *p;
|
const char* p;
|
||||||
for (p = start; p < end; ++p) {
|
for (p = start; p < end; ++p) {
|
||||||
int ch = *p;
|
int ch = *p;
|
||||||
if ((ch >= '0' && ch <= '9') ||
|
if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') ||
|
||||||
(ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')) {
|
(ch >= 'a' && ch <= 'f')) {
|
||||||
*hex = (*hex << 4U) | (ch < 'A' ? static_cast<uint64_t>(ch - '0') : (ch & 0xF) + 9U);
|
*hex = (*hex << 4U) |
|
||||||
|
(ch < 'A' ? static_cast<uint64_t>(ch - '0') : (ch & 0xF) + 9U);
|
||||||
} else { // Encountered the first non-hex character.
|
} else { // Encountered the first non-hex character.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SAFE_ASSERT(p <= end);
|
SAFE_ASSERT(p <= end);
|
||||||
return const_cast<char *>(p);
|
return const_cast<char*>(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Searches for the object file (from /proc/self/maps) that contains
|
// Searches for the object file (from /proc/self/maps) that contains
|
||||||
@ -512,12 +512,9 @@ static char *GetHex(const char *start, const char *end, uint64_t *hex) {
|
|||||||
// file is opened successfully, returns the file descriptor. Otherwise,
|
// file is opened successfully, returns the file descriptor. Otherwise,
|
||||||
// returns -1. |out_file_name_size| is the size of the file name buffer
|
// returns -1. |out_file_name_size| is the size of the file name buffer
|
||||||
// (including the null-terminator).
|
// (including the null-terminator).
|
||||||
static ATTRIBUTE_NOINLINE int
|
static ATTRIBUTE_NOINLINE int OpenObjectFileContainingPcAndGetStartAddress(
|
||||||
OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
|
uint64_t pc, uint64_t& start_address, uint64_t& base_address,
|
||||||
uint64_t &start_address,
|
char* out_file_name, size_t out_file_name_size) {
|
||||||
uint64_t &base_address,
|
|
||||||
char *out_file_name,
|
|
||||||
size_t out_file_name_size) {
|
|
||||||
int object_fd;
|
int object_fd;
|
||||||
|
|
||||||
int maps_fd;
|
int maps_fd;
|
||||||
@ -539,8 +536,8 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
|
|||||||
char buf[1024]; // Big enough for line of sane /proc/self/maps
|
char buf[1024]; // Big enough for line of sane /proc/self/maps
|
||||||
LineReader reader(wrapped_maps_fd.get(), buf, sizeof(buf), 0);
|
LineReader reader(wrapped_maps_fd.get(), buf, sizeof(buf), 0);
|
||||||
while (true) {
|
while (true) {
|
||||||
const char *cursor;
|
const char* cursor;
|
||||||
const char *eol;
|
const char* eol;
|
||||||
if (!reader.ReadLine(&cursor, &eol)) { // EOF or malformed line.
|
if (!reader.ReadLine(&cursor, &eol)) { // EOF or malformed line.
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -568,7 +565,7 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
|
|||||||
++cursor; // Skip ' '.
|
++cursor; // Skip ' '.
|
||||||
|
|
||||||
// Read flags. Skip flags until we encounter a space or eol.
|
// Read flags. Skip flags until we encounter a space or eol.
|
||||||
const char * const flags_start = cursor;
|
const char* const flags_start = cursor;
|
||||||
while (cursor < eol && *cursor != ' ') {
|
while (cursor < eol && *cursor != ' ') {
|
||||||
++cursor;
|
++cursor;
|
||||||
}
|
}
|
||||||
@ -620,7 +617,7 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
|
|||||||
continue; // We skip this map. PC isn't in this map.
|
continue; // We skip this map. PC isn't in this map.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check flags. We are only interested in "r*x" maps.
|
// Check flags. We are only interested in "r*x" maps.
|
||||||
if (flags_start[0] != 'r' || flags_start[2] != 'x') {
|
if (flags_start[0] != 'r' || flags_start[2] != 'x') {
|
||||||
continue; // We skip this map.
|
continue; // We skip this map.
|
||||||
}
|
}
|
||||||
@ -672,7 +669,8 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
|
|||||||
// "sz" bytes. Output will be truncated as needed, and a NUL character is always
|
// "sz" bytes. Output will be truncated as needed, and a NUL character is always
|
||||||
// appended.
|
// appended.
|
||||||
// NOTE: code from sandbox/linux/seccomp-bpf/demo.cc.
|
// NOTE: code from sandbox/linux/seccomp-bpf/demo.cc.
|
||||||
static char *itoa_r(uintptr_t i, char *buf, size_t sz, unsigned base, size_t padding) {
|
static char* itoa_r(uintptr_t i, char* buf, size_t sz, unsigned base,
|
||||||
|
size_t padding) {
|
||||||
// Make sure we can write at least one NUL byte.
|
// Make sure we can write at least one NUL byte.
|
||||||
size_t n = 1;
|
size_t n = 1;
|
||||||
if (n > sz) {
|
if (n > sz) {
|
||||||
@ -684,11 +682,11 @@ static char *itoa_r(uintptr_t i, char *buf, size_t sz, unsigned base, size_t pad
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *start = buf;
|
char* start = buf;
|
||||||
|
|
||||||
// Loop until we have converted the entire number. Output at least one
|
// Loop until we have converted the entire number. Output at least one
|
||||||
// character (i.e. '0').
|
// character (i.e. '0').
|
||||||
char *ptr = start;
|
char* ptr = start;
|
||||||
do {
|
do {
|
||||||
// Make sure there is still enough space left in our output buffer.
|
// Make sure there is still enough space left in our output buffer.
|
||||||
if (++n > sz) {
|
if (++n > sz) {
|
||||||
@ -749,7 +747,7 @@ static void SafeAppendHexNumber(uint64_t value, char* dest, size_t dest_size) {
|
|||||||
// and "out" is used as its output.
|
// and "out" is used as its output.
|
||||||
// To keep stack consumption low, we would like this function to not
|
// To keep stack consumption low, we would like this function to not
|
||||||
// get inlined.
|
// get inlined.
|
||||||
static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
|
static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void* pc, char* out,
|
||||||
size_t out_size) {
|
size_t out_size) {
|
||||||
auto pc0 = reinterpret_cast<uintptr_t>(pc);
|
auto pc0 = reinterpret_cast<uintptr_t>(pc);
|
||||||
uint64_t start_address = 0;
|
uint64_t start_address = 0;
|
||||||
@ -763,24 +761,21 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
|
|||||||
SafeAppendString("(", out, out_size);
|
SafeAppendString("(", out, out_size);
|
||||||
|
|
||||||
if (g_symbolize_open_object_file_callback) {
|
if (g_symbolize_open_object_file_callback) {
|
||||||
object_fd = g_symbolize_open_object_file_callback(pc0, start_address,
|
object_fd = g_symbolize_open_object_file_callback(
|
||||||
base_address, out + 1,
|
pc0, start_address, base_address, out + 1, out_size - 1);
|
||||||
out_size - 1);
|
|
||||||
} else {
|
} else {
|
||||||
object_fd = OpenObjectFileContainingPcAndGetStartAddress(pc0, start_address,
|
object_fd = OpenObjectFileContainingPcAndGetStartAddress(
|
||||||
base_address,
|
pc0, start_address, base_address, out + 1, out_size - 1);
|
||||||
out + 1,
|
|
||||||
out_size - 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FileDescriptor wrapped_object_fd(object_fd);
|
FileDescriptor wrapped_object_fd(object_fd);
|
||||||
|
|
||||||
#if defined(PRINT_UNSYMBOLIZED_STACK_TRACES)
|
# if defined(PRINT_UNSYMBOLIZED_STACK_TRACES)
|
||||||
{
|
{
|
||||||
#else
|
# else
|
||||||
// Check whether a file name was returned.
|
// Check whether a file name was returned.
|
||||||
if (object_fd < 0) {
|
if (object_fd < 0) {
|
||||||
#endif
|
# endif
|
||||||
if (out[1]) {
|
if (out[1]) {
|
||||||
// The object file containing PC was determined successfully however the
|
// The object file containing PC was determined successfully however the
|
||||||
// object file was not opened successfully. This is still considered
|
// object file was not opened successfully. This is still considered
|
||||||
@ -804,16 +799,15 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
|
|||||||
// Note: relocation (and much of the rest of this code) will be
|
// Note: relocation (and much of the rest of this code) will be
|
||||||
// wrong for prelinked shared libraries and PIE executables.
|
// wrong for prelinked shared libraries and PIE executables.
|
||||||
uint64_t relocation = (elf_type == ET_DYN) ? start_address : 0;
|
uint64_t relocation = (elf_type == ET_DYN) ? start_address : 0;
|
||||||
int num_bytes_written = g_symbolize_callback(wrapped_object_fd.get(),
|
int num_bytes_written = g_symbolize_callback(wrapped_object_fd.get(), pc,
|
||||||
pc, out, out_size,
|
out, out_size, relocation);
|
||||||
relocation);
|
|
||||||
if (num_bytes_written > 0) {
|
if (num_bytes_written > 0) {
|
||||||
out += static_cast<size_t>(num_bytes_written);
|
out += static_cast<size_t>(num_bytes_written);
|
||||||
out_size -= static_cast<size_t>(num_bytes_written);
|
out_size -= static_cast<size_t>(num_bytes_written);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!GetSymbolFromObjectFile(wrapped_object_fd.get(), pc0,
|
if (!GetSymbolFromObjectFile(wrapped_object_fd.get(), pc0, out, out_size,
|
||||||
out, out_size, base_address)) {
|
base_address)) {
|
||||||
if (out[1] && !g_symbolize_callback) {
|
if (out[1] && !g_symbolize_callback) {
|
||||||
// The object file containing PC was opened successfully however the
|
// The object file containing PC was opened successfully however the
|
||||||
// symbol was not found. The object may have been stripped. This is still
|
// symbol was not found. The object may have been stripped. This is still
|
||||||
@ -835,14 +829,15 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
|
|||||||
|
|
||||||
} // namespace google
|
} // namespace google
|
||||||
|
|
||||||
#elif defined(GLOG_OS_MACOSX) && defined(HAVE_DLADDR)
|
# elif defined(GLOG_OS_MACOSX) && defined(HAVE_DLADDR)
|
||||||
|
|
||||||
#include <dlfcn.h>
|
# include <dlfcn.h>
|
||||||
#include <cstring>
|
|
||||||
|
# include <cstring>
|
||||||
|
|
||||||
namespace google {
|
namespace google {
|
||||||
|
|
||||||
static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
|
static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void* pc, char* out,
|
||||||
size_t out_size) {
|
size_t out_size) {
|
||||||
Dl_info info;
|
Dl_info info;
|
||||||
if (dladdr(pc, &info)) {
|
if (dladdr(pc, &info)) {
|
||||||
@ -860,19 +855,19 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
|
|||||||
|
|
||||||
} // namespace google
|
} // namespace google
|
||||||
|
|
||||||
#elif defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)
|
# elif defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)
|
||||||
|
|
||||||
#include <windows.h>
|
# include <dbghelp.h>
|
||||||
#include <dbghelp.h>
|
# include <windows.h>
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
# ifdef _MSC_VER
|
||||||
#pragma comment(lib, "dbghelp")
|
# pragma comment(lib, "dbghelp")
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
namespace google {
|
namespace google {
|
||||||
|
|
||||||
class SymInitializer {
|
class SymInitializer {
|
||||||
public:
|
public:
|
||||||
HANDLE process;
|
HANDLE process;
|
||||||
bool ready;
|
bool ready;
|
||||||
SymInitializer() : process(nullptr), ready(false) {
|
SymInitializer() : process(nullptr), ready(false) {
|
||||||
@ -891,12 +886,13 @@ public:
|
|||||||
SymCleanup(process);
|
SymCleanup(process);
|
||||||
// We do not need to close `HANDLE process` because it's a "pseudo handle."
|
// We do not need to close `HANDLE process` because it's a "pseudo handle."
|
||||||
}
|
}
|
||||||
private:
|
|
||||||
|
private:
|
||||||
SymInitializer(const SymInitializer&);
|
SymInitializer(const SymInitializer&);
|
||||||
SymInitializer& operator=(const SymInitializer&);
|
SymInitializer& operator=(const SymInitializer&);
|
||||||
};
|
};
|
||||||
|
|
||||||
static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
|
static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void* pc, char* out,
|
||||||
size_t out_size) {
|
size_t out_size) {
|
||||||
const static SymInitializer symInitializer;
|
const static SymInitializer symInitializer;
|
||||||
if (!symInitializer.ready) {
|
if (!symInitializer.ready) {
|
||||||
@ -905,13 +901,13 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
|
|||||||
// Resolve symbol information from address.
|
// Resolve symbol information from address.
|
||||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680578(v=vs.85).aspx
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680578(v=vs.85).aspx
|
||||||
char buf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
|
char buf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
|
||||||
SYMBOL_INFO *symbol = reinterpret_cast<SYMBOL_INFO *>(buf);
|
SYMBOL_INFO* symbol = reinterpret_cast<SYMBOL_INFO*>(buf);
|
||||||
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||||
symbol->MaxNameLen = MAX_SYM_NAME;
|
symbol->MaxNameLen = MAX_SYM_NAME;
|
||||||
// We use the ANSI version to ensure the string type is always `char *`.
|
// We use the ANSI version to ensure the string type is always `char *`.
|
||||||
// This could break if a symbol has Unicode in it.
|
// This could break if a symbol has Unicode in it.
|
||||||
BOOL ret = SymFromAddr(symInitializer.process,
|
BOOL ret = SymFromAddr(symInitializer.process, reinterpret_cast<DWORD64>(pc),
|
||||||
reinterpret_cast<DWORD64>(pc), 0, symbol);
|
0, symbol);
|
||||||
if (ret == 1 && static_cast<ssize_t>(symbol->NameLen) < out_size) {
|
if (ret == 1 && static_cast<ssize_t>(symbol->NameLen) < out_size) {
|
||||||
// `NameLen` does not include the null terminating character.
|
// `NameLen` does not include the null terminating character.
|
||||||
strncpy(out, symbol->Name, static_cast<size_t>(symbol->NameLen) + 1);
|
strncpy(out, symbol->Name, static_cast<size_t>(symbol->NameLen) + 1);
|
||||||
@ -925,23 +921,23 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
|
|||||||
|
|
||||||
} // namespace google
|
} // namespace google
|
||||||
|
|
||||||
#else
|
# else
|
||||||
# error BUG: HAVE_SYMBOLIZE was wrongly set
|
# error BUG: HAVE_SYMBOLIZE was wrongly set
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
namespace google {
|
namespace google {
|
||||||
|
|
||||||
bool Symbolize(void *pc, char *out, size_t out_size) {
|
bool Symbolize(void* pc, char* out, size_t out_size) {
|
||||||
return SymbolizeAndDemangle(pc, out, out_size);
|
return SymbolizeAndDemangle(pc, out, out_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace google
|
} // namespace google
|
||||||
|
|
||||||
#else /* HAVE_SYMBOLIZE */
|
#else /* HAVE_SYMBOLIZE */
|
||||||
|
|
||||||
#include <cassert>
|
# include <cassert>
|
||||||
|
|
||||||
#include "config.h"
|
# include "config.h"
|
||||||
|
|
||||||
namespace google {
|
namespace google {
|
||||||
|
|
||||||
|
|||||||
@ -60,48 +60,48 @@
|
|||||||
|
|
||||||
#ifdef HAVE_SYMBOLIZE
|
#ifdef HAVE_SYMBOLIZE
|
||||||
|
|
||||||
#if defined(__ELF__) // defined by gcc
|
# if defined(__ELF__) // defined by gcc
|
||||||
#if defined(__OpenBSD__)
|
# if defined(__OpenBSD__)
|
||||||
#include <sys/exec_elf.h>
|
# include <sys/exec_elf.h>
|
||||||
#else
|
# else
|
||||||
#include <elf.h>
|
# include <elf.h>
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
#if !defined(ANDROID)
|
# if !defined(ANDROID)
|
||||||
#include <link.h> // For ElfW() macro.
|
# include <link.h> // For ElfW() macro.
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
// For systems where SIZEOF_VOID_P is not defined, determine it
|
// For systems where SIZEOF_VOID_P is not defined, determine it
|
||||||
// based on __LP64__ (defined by gcc on 64-bit systems)
|
// based on __LP64__ (defined by gcc on 64-bit systems)
|
||||||
#if !defined(SIZEOF_VOID_P)
|
# if !defined(SIZEOF_VOID_P)
|
||||||
# if defined(__LP64__)
|
# if defined(__LP64__)
|
||||||
# define SIZEOF_VOID_P 8
|
# define SIZEOF_VOID_P 8
|
||||||
# else
|
# else
|
||||||
# define SIZEOF_VOID_P 4
|
# define SIZEOF_VOID_P 4
|
||||||
# endif
|
# endif
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
// If there is no ElfW macro, let's define it by ourself.
|
// If there is no ElfW macro, let's define it by ourself.
|
||||||
#ifndef ElfW
|
# ifndef ElfW
|
||||||
# if SIZEOF_VOID_P == 4
|
# if SIZEOF_VOID_P == 4
|
||||||
# define ElfW(type) Elf32_##type
|
# define ElfW(type) Elf32_##type
|
||||||
# elif SIZEOF_VOID_P == 8
|
# elif SIZEOF_VOID_P == 8
|
||||||
# define ElfW(type) Elf64_##type
|
# define ElfW(type) Elf64_##type
|
||||||
# else
|
# else
|
||||||
# error "Unknown sizeof(void *)"
|
# error "Unknown sizeof(void *)"
|
||||||
# endif
|
# endif
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
namespace google {
|
namespace google {
|
||||||
|
|
||||||
// Gets the section header for the given name, if it exists. Returns true on
|
// Gets the section header for the given name, if it exists. Returns true on
|
||||||
// success. Otherwise, returns false.
|
// success. Otherwise, returns false.
|
||||||
bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
|
bool GetSectionHeaderByName(int fd, const char* name, size_t name_len,
|
||||||
ElfW(Shdr) *out);
|
ElfW(Shdr) * out);
|
||||||
|
|
||||||
} // namespace google
|
} // namespace google
|
||||||
|
|
||||||
#endif /* __ELF__ */
|
# endif /* __ELF__ */
|
||||||
|
|
||||||
namespace google {
|
namespace google {
|
||||||
|
|
||||||
@ -116,7 +116,7 @@ namespace google {
|
|||||||
// counter "pc". The callback function should write output to "out"
|
// counter "pc". The callback function should write output to "out"
|
||||||
// and return the size of the output written. On error, the callback
|
// and return the size of the output written. On error, the callback
|
||||||
// function should return -1.
|
// function should return -1.
|
||||||
using SymbolizeCallback = int (*)(int, void *, char *, size_t, uint64_t);
|
using SymbolizeCallback = int (*)(int, void*, char*, size_t, uint64_t);
|
||||||
GLOG_EXPORT
|
GLOG_EXPORT
|
||||||
void InstallSymbolizeCallback(SymbolizeCallback callback);
|
void InstallSymbolizeCallback(SymbolizeCallback callback);
|
||||||
|
|
||||||
@ -130,8 +130,8 @@ void InstallSymbolizeCallback(SymbolizeCallback callback);
|
|||||||
// file is opened successfully, returns the file descriptor. Otherwise,
|
// file is opened successfully, returns the file descriptor. Otherwise,
|
||||||
// returns -1. |out_file_name_size| is the size of the file name buffer
|
// returns -1. |out_file_name_size| is the size of the file name buffer
|
||||||
// (including the null-terminator).
|
// (including the null-terminator).
|
||||||
using SymbolizeOpenObjectFileCallback = int (*)(uint64_t, uint64_t &,
|
using SymbolizeOpenObjectFileCallback = int (*)(uint64_t, uint64_t&, uint64_t&,
|
||||||
uint64_t &, char *, size_t);
|
char*, size_t);
|
||||||
void InstallSymbolizeOpenObjectFileCallback(
|
void InstallSymbolizeOpenObjectFileCallback(
|
||||||
SymbolizeOpenObjectFileCallback callback);
|
SymbolizeOpenObjectFileCallback callback);
|
||||||
|
|
||||||
|
|||||||
@ -42,7 +42,7 @@
|
|||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
|
||||||
#ifdef GLOG_USE_GFLAGS
|
#ifdef GLOG_USE_GFLAGS
|
||||||
#include <gflags/gflags.h>
|
# include <gflags/gflags.h>
|
||||||
using namespace GFLAGS_NAMESPACE;
|
using namespace GFLAGS_NAMESPACE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -52,17 +52,17 @@ using namespace google;
|
|||||||
// Avoid compile error due to "cast between pointer-to-function and
|
// Avoid compile error due to "cast between pointer-to-function and
|
||||||
// pointer-to-object is an extension" warnings.
|
// pointer-to-object is an extension" warnings.
|
||||||
#if defined(__GNUG__)
|
#if defined(__GNUG__)
|
||||||
#pragma GCC diagnostic push
|
# pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wpedantic"
|
# pragma GCC diagnostic ignored "-Wpedantic"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(HAVE_STACKTRACE)
|
#if defined(HAVE_STACKTRACE)
|
||||||
|
|
||||||
#define always_inline
|
# define always_inline
|
||||||
|
|
||||||
#if defined(__ELF__) || defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)
|
# if defined(__ELF__) || defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)
|
||||||
// A wrapper function for Symbolize() to make the unit test simple.
|
// A wrapper function for Symbolize() to make the unit test simple.
|
||||||
static const char *TrySymbolize(void *pc) {
|
static const char* TrySymbolize(void* pc) {
|
||||||
static char symbol[4096];
|
static char symbol[4096];
|
||||||
if (Symbolize(pc, symbol, sizeof(symbol))) {
|
if (Symbolize(pc, symbol, sizeof(symbol))) {
|
||||||
return symbol;
|
return symbol;
|
||||||
@ -70,24 +70,25 @@ static const char *TrySymbolize(void *pc) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
# if defined(__ELF__)
|
# if defined(__ELF__)
|
||||||
|
|
||||||
// This unit tests make sense only with GCC.
|
// This unit tests make sense only with GCC.
|
||||||
// Uses lots of GCC specific features.
|
// Uses lots of GCC specific features.
|
||||||
#if defined(__GNUC__) && !defined(__OPENCC__)
|
# if defined(__GNUC__) && !defined(__OPENCC__)
|
||||||
# if __GNUC__ >= 4
|
# if __GNUC__ >= 4
|
||||||
# define TEST_WITH_MODERN_GCC
|
# define TEST_WITH_MODERN_GCC
|
||||||
# if defined(__i386__) && __i386__ // always_inline isn't supported for x86_64 with GCC 4.1.0.
|
# if defined(__i386__) && __i386__ // always_inline isn't supported for
|
||||||
# undef always_inline
|
// x86_64 with GCC 4.1.0.
|
||||||
# define always_inline __attribute__((always_inline))
|
# undef always_inline
|
||||||
# define HAVE_ALWAYS_INLINE
|
# define always_inline __attribute__((always_inline))
|
||||||
# endif // __i386__
|
# define HAVE_ALWAYS_INLINE
|
||||||
# else
|
# endif // __i386__
|
||||||
# endif // __GNUC__ >= 4
|
# else
|
||||||
# define TEST_WITH_LABEL_ADDRESSES
|
# endif // __GNUC__ >= 4
|
||||||
#endif
|
# define TEST_WITH_LABEL_ADDRESSES
|
||||||
|
# endif
|
||||||
|
|
||||||
// Make them C linkage to avoid mangled names.
|
// Make them C linkage to avoid mangled names.
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -112,18 +113,18 @@ TEST(Symbolize, Symbolize) {
|
|||||||
// reinterpret_cast<void *>(&func).
|
// reinterpret_cast<void *>(&func).
|
||||||
|
|
||||||
// Compilers should give us pointers to them.
|
// Compilers should give us pointers to them.
|
||||||
EXPECT_STREQ("nonstatic_func", TrySymbolize((void *)(&nonstatic_func)));
|
EXPECT_STREQ("nonstatic_func", TrySymbolize((void*)(&nonstatic_func)));
|
||||||
|
|
||||||
// The name of an internal linkage symbol is not specified; allow either a
|
// The name of an internal linkage symbol is not specified; allow either a
|
||||||
// mangled or an unmangled name here.
|
// mangled or an unmangled name here.
|
||||||
const char *static_func_symbol =
|
const char* static_func_symbol =
|
||||||
TrySymbolize(reinterpret_cast<void *>(&static_func));
|
TrySymbolize(reinterpret_cast<void*>(&static_func));
|
||||||
|
|
||||||
#if !defined(_MSC_VER) || !defined(NDEBUG)
|
# if !defined(_MSC_VER) || !defined(NDEBUG)
|
||||||
CHECK(nullptr != static_func_symbol);
|
CHECK(nullptr != static_func_symbol);
|
||||||
EXPECT_TRUE(strcmp("static_func", static_func_symbol) == 0 ||
|
EXPECT_TRUE(strcmp("static_func", static_func_symbol) == 0 ||
|
||||||
strcmp("static_func()", static_func_symbol) == 0);
|
strcmp("static_func()", static_func_symbol) == 0);
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
EXPECT_TRUE(nullptr == TrySymbolize(nullptr));
|
EXPECT_TRUE(nullptr == TrySymbolize(nullptr));
|
||||||
}
|
}
|
||||||
@ -141,14 +142,14 @@ void ATTRIBUTE_NOINLINE Foo::func(int x) {
|
|||||||
|
|
||||||
// With a modern GCC, Symbolize() should return demangled symbol
|
// With a modern GCC, Symbolize() should return demangled symbol
|
||||||
// names. Function parameters should be omitted.
|
// names. Function parameters should be omitted.
|
||||||
#ifdef TEST_WITH_MODERN_GCC
|
# ifdef TEST_WITH_MODERN_GCC
|
||||||
TEST(Symbolize, SymbolizeWithDemangling) {
|
TEST(Symbolize, SymbolizeWithDemangling) {
|
||||||
Foo::func(100);
|
Foo::func(100);
|
||||||
#if !defined(_MSC_VER) || !defined(NDEBUG)
|
# if !defined(_MSC_VER) || !defined(NDEBUG)
|
||||||
EXPECT_STREQ("Foo::func()", TrySymbolize((void *)(&Foo::func)));
|
EXPECT_STREQ("Foo::func()", TrySymbolize((void*)(&Foo::func)));
|
||||||
#endif
|
# endif
|
||||||
}
|
}
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
// Tests that verify that Symbolize footprint is within some limit.
|
// Tests that verify that Symbolize footprint is within some limit.
|
||||||
|
|
||||||
@ -167,9 +168,9 @@ TEST(Symbolize, SymbolizeWithDemangling) {
|
|||||||
// calls Symbolize. The difference between the stack consumption of these
|
// calls Symbolize. The difference between the stack consumption of these
|
||||||
// two signals handlers should give us the Symbolize stack foorprint.
|
// two signals handlers should give us the Symbolize stack foorprint.
|
||||||
|
|
||||||
static void *g_pc_to_symbolize;
|
static void* g_pc_to_symbolize;
|
||||||
static char g_symbolize_buffer[4096];
|
static char g_symbolize_buffer[4096];
|
||||||
static char *g_symbolize_result;
|
static char* g_symbolize_result;
|
||||||
|
|
||||||
static void EmptySignalHandler(int /*signo*/) {}
|
static void EmptySignalHandler(int /*signo*/) {}
|
||||||
|
|
||||||
@ -188,7 +189,7 @@ const char kAlternateStackFillValue = 0x55;
|
|||||||
// These helper functions look at the alternate stack buffer, and figure
|
// These helper functions look at the alternate stack buffer, and figure
|
||||||
// out what portion of this buffer has been touched - this is the stack
|
// out what portion of this buffer has been touched - this is the stack
|
||||||
// consumption of the signal handler running on this alternate stack.
|
// consumption of the signal handler running on this alternate stack.
|
||||||
static ATTRIBUTE_NOINLINE bool StackGrowsDown(int *x) {
|
static ATTRIBUTE_NOINLINE bool StackGrowsDown(int* x) {
|
||||||
int y;
|
int y;
|
||||||
return &y < x;
|
return &y < x;
|
||||||
}
|
}
|
||||||
@ -210,11 +211,10 @@ static int GetStackConsumption(const char* alt_stack) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_SIGALTSTACK
|
# ifdef HAVE_SIGALTSTACK
|
||||||
|
|
||||||
// Call Symbolize and figure out the stack footprint of this call.
|
// Call Symbolize and figure out the stack footprint of this call.
|
||||||
static const char *SymbolizeStackConsumption(void *pc, int *stack_consumed) {
|
static const char* SymbolizeStackConsumption(void* pc, int* stack_consumed) {
|
||||||
|
|
||||||
g_pc_to_symbolize = pc;
|
g_pc_to_symbolize = pc;
|
||||||
|
|
||||||
// The alt-signal-stack cannot be heap allocated because there is a
|
// The alt-signal-stack cannot be heap allocated because there is a
|
||||||
@ -282,19 +282,19 @@ static const char *SymbolizeStackConsumption(void *pc, int *stack_consumed) {
|
|||||||
return g_symbolize_result;
|
return g_symbolize_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __ppc64__
|
# ifdef __ppc64__
|
||||||
// Symbolize stack consumption should be within 4kB.
|
// Symbolize stack consumption should be within 4kB.
|
||||||
const int kStackConsumptionUpperLimit = 4096;
|
const int kStackConsumptionUpperLimit = 4096;
|
||||||
#else
|
# else
|
||||||
// Symbolize stack consumption should be within 2kB.
|
// Symbolize stack consumption should be within 2kB.
|
||||||
const int kStackConsumptionUpperLimit = 2048;
|
const int kStackConsumptionUpperLimit = 2048;
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
TEST(Symbolize, SymbolizeStackConsumption) {
|
TEST(Symbolize, SymbolizeStackConsumption) {
|
||||||
int stack_consumed;
|
int stack_consumed;
|
||||||
const char* symbol;
|
const char* symbol;
|
||||||
|
|
||||||
symbol = SymbolizeStackConsumption(reinterpret_cast<void *>(&nonstatic_func),
|
symbol = SymbolizeStackConsumption(reinterpret_cast<void*>(&nonstatic_func),
|
||||||
&stack_consumed);
|
&stack_consumed);
|
||||||
EXPECT_STREQ("nonstatic_func", symbol);
|
EXPECT_STREQ("nonstatic_func", symbol);
|
||||||
EXPECT_GT(stack_consumed, 0);
|
EXPECT_GT(stack_consumed, 0);
|
||||||
@ -302,7 +302,7 @@ TEST(Symbolize, SymbolizeStackConsumption) {
|
|||||||
|
|
||||||
// The name of an internal linkage symbol is not specified; allow either a
|
// The name of an internal linkage symbol is not specified; allow either a
|
||||||
// mangled or an unmangled name here.
|
// mangled or an unmangled name here.
|
||||||
symbol = SymbolizeStackConsumption(reinterpret_cast<void *>(&static_func),
|
symbol = SymbolizeStackConsumption(reinterpret_cast<void*>(&static_func),
|
||||||
&stack_consumed);
|
&stack_consumed);
|
||||||
CHECK(nullptr != symbol);
|
CHECK(nullptr != symbol);
|
||||||
EXPECT_TRUE(strcmp("static_func", symbol) == 0 ||
|
EXPECT_TRUE(strcmp("static_func", symbol) == 0 ||
|
||||||
@ -311,91 +311,91 @@ TEST(Symbolize, SymbolizeStackConsumption) {
|
|||||||
EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
|
EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TEST_WITH_MODERN_GCC
|
# ifdef TEST_WITH_MODERN_GCC
|
||||||
TEST(Symbolize, SymbolizeWithDemanglingStackConsumption) {
|
TEST(Symbolize, SymbolizeWithDemanglingStackConsumption) {
|
||||||
Foo::func(100);
|
Foo::func(100);
|
||||||
int stack_consumed;
|
int stack_consumed;
|
||||||
const char* symbol;
|
const char* symbol;
|
||||||
|
|
||||||
symbol = SymbolizeStackConsumption(reinterpret_cast<void *>(&Foo::func),
|
symbol = SymbolizeStackConsumption(reinterpret_cast<void*>(&Foo::func),
|
||||||
&stack_consumed);
|
&stack_consumed);
|
||||||
|
|
||||||
EXPECT_STREQ("Foo::func()", symbol);
|
EXPECT_STREQ("Foo::func()", symbol);
|
||||||
EXPECT_GT(stack_consumed, 0);
|
EXPECT_GT(stack_consumed, 0);
|
||||||
EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
|
EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
|
||||||
}
|
}
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
#endif // HAVE_SIGALTSTACK
|
# endif // HAVE_SIGALTSTACK
|
||||||
|
|
||||||
// x86 specific tests. Uses some inline assembler.
|
// x86 specific tests. Uses some inline assembler.
|
||||||
extern "C" {
|
extern "C" {
|
||||||
inline void* always_inline inline_func() {
|
inline void* always_inline inline_func() {
|
||||||
void *pc = nullptr;
|
void* pc = nullptr;
|
||||||
#ifdef TEST_WITH_LABEL_ADDRESSES
|
# ifdef TEST_WITH_LABEL_ADDRESSES
|
||||||
pc = &&curr_pc;
|
pc = &&curr_pc;
|
||||||
curr_pc:
|
curr_pc:
|
||||||
#endif
|
# endif
|
||||||
return pc;
|
return pc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* ATTRIBUTE_NOINLINE non_inline_func();
|
void* ATTRIBUTE_NOINLINE non_inline_func();
|
||||||
void* ATTRIBUTE_NOINLINE non_inline_func() {
|
void* ATTRIBUTE_NOINLINE non_inline_func() {
|
||||||
void *pc = nullptr;
|
void* pc = nullptr;
|
||||||
#ifdef TEST_WITH_LABEL_ADDRESSES
|
# ifdef TEST_WITH_LABEL_ADDRESSES
|
||||||
pc = &&curr_pc;
|
pc = &&curr_pc;
|
||||||
curr_pc:
|
curr_pc:
|
||||||
#endif
|
# endif
|
||||||
return pc;
|
return pc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ATTRIBUTE_NOINLINE TestWithPCInsideNonInlineFunction() {
|
static void ATTRIBUTE_NOINLINE TestWithPCInsideNonInlineFunction() {
|
||||||
#if defined(TEST_WITH_LABEL_ADDRESSES) && defined(HAVE_ATTRIBUTE_NOINLINE)
|
# if defined(TEST_WITH_LABEL_ADDRESSES) && defined(HAVE_ATTRIBUTE_NOINLINE)
|
||||||
void *pc = non_inline_func();
|
void* pc = non_inline_func();
|
||||||
const char *symbol = TrySymbolize(pc);
|
const char* symbol = TrySymbolize(pc);
|
||||||
|
|
||||||
#if !defined(_MSC_VER) || !defined(NDEBUG)
|
# if !defined(_MSC_VER) || !defined(NDEBUG)
|
||||||
CHECK(symbol != nullptr);
|
CHECK(symbol != nullptr);
|
||||||
CHECK_STREQ(symbol, "non_inline_func");
|
CHECK_STREQ(symbol, "non_inline_func");
|
||||||
#endif
|
# endif
|
||||||
cout << "Test case TestWithPCInsideNonInlineFunction passed." << endl;
|
cout << "Test case TestWithPCInsideNonInlineFunction passed." << endl;
|
||||||
#endif
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ATTRIBUTE_NOINLINE TestWithPCInsideInlineFunction() {
|
static void ATTRIBUTE_NOINLINE TestWithPCInsideInlineFunction() {
|
||||||
#if defined(TEST_WITH_LABEL_ADDRESSES) && defined(HAVE_ALWAYS_INLINE)
|
# if defined(TEST_WITH_LABEL_ADDRESSES) && defined(HAVE_ALWAYS_INLINE)
|
||||||
void *pc = inline_func(); // Must be inlined.
|
void* pc = inline_func(); // Must be inlined.
|
||||||
const char *symbol = TrySymbolize(pc);
|
const char* symbol = TrySymbolize(pc);
|
||||||
|
|
||||||
#if !defined(_MSC_VER) || !defined(NDEBUG)
|
# if !defined(_MSC_VER) || !defined(NDEBUG)
|
||||||
CHECK(symbol != nullptr);
|
CHECK(symbol != nullptr);
|
||||||
CHECK_STREQ(symbol, __FUNCTION__);
|
CHECK_STREQ(symbol, __FUNCTION__);
|
||||||
#endif
|
# endif
|
||||||
cout << "Test case TestWithPCInsideInlineFunction passed." << endl;
|
cout << "Test case TestWithPCInsideInlineFunction passed." << endl;
|
||||||
#endif
|
# endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test with a return address.
|
// Test with a return address.
|
||||||
static void ATTRIBUTE_NOINLINE TestWithReturnAddress() {
|
static void ATTRIBUTE_NOINLINE TestWithReturnAddress() {
|
||||||
#if defined(HAVE_ATTRIBUTE_NOINLINE)
|
# if defined(HAVE_ATTRIBUTE_NOINLINE)
|
||||||
void *return_address = __builtin_return_address(0);
|
void* return_address = __builtin_return_address(0);
|
||||||
const char *symbol = TrySymbolize(return_address);
|
const char* symbol = TrySymbolize(return_address);
|
||||||
|
|
||||||
#if !defined(_MSC_VER) || !defined(NDEBUG)
|
# if !defined(_MSC_VER) || !defined(NDEBUG)
|
||||||
CHECK(symbol != nullptr);
|
CHECK(symbol != nullptr);
|
||||||
CHECK_STREQ(symbol, "main");
|
CHECK_STREQ(symbol, "main");
|
||||||
#endif
|
# endif
|
||||||
cout << "Test case TestWithReturnAddress passed." << endl;
|
cout << "Test case TestWithReturnAddress passed." << endl;
|
||||||
#endif
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
# elif defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)
|
# elif defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
# ifdef _MSC_VER
|
||||||
#include <intrin.h>
|
# include <intrin.h>
|
||||||
#pragma intrinsic(_ReturnAddress)
|
# pragma intrinsic(_ReturnAddress)
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
struct Foo {
|
struct Foo {
|
||||||
static void func(int x);
|
static void func(int x);
|
||||||
@ -410,37 +410,37 @@ __declspec(noinline) void Foo::func(int x) {
|
|||||||
|
|
||||||
TEST(Symbolize, SymbolizeWithDemangling) {
|
TEST(Symbolize, SymbolizeWithDemangling) {
|
||||||
Foo::func(100);
|
Foo::func(100);
|
||||||
const char* ret = TrySymbolize((void *)(&Foo::func));
|
const char* ret = TrySymbolize((void*)(&Foo::func));
|
||||||
|
|
||||||
#if defined(HAVE_DBGHELP) && !defined(NDEBUG)
|
# if defined(HAVE_DBGHELP) && !defined(NDEBUG)
|
||||||
EXPECT_STREQ("public: static void __cdecl Foo::func(int)", ret);
|
EXPECT_STREQ("public: static void __cdecl Foo::func(int)", ret);
|
||||||
#endif
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
__declspec(noinline) void TestWithReturnAddress() {
|
__declspec(noinline) void TestWithReturnAddress() {
|
||||||
void *return_address =
|
void* return_address =
|
||||||
#ifdef __GNUC__ // Cygwin and MinGW support
|
# ifdef __GNUC__ // Cygwin and MinGW support
|
||||||
__builtin_return_address(0)
|
__builtin_return_address(0)
|
||||||
#else
|
# else
|
||||||
_ReturnAddress()
|
_ReturnAddress()
|
||||||
#endif
|
# endif
|
||||||
;
|
;
|
||||||
const char *symbol = TrySymbolize(return_address);
|
const char* symbol = TrySymbolize(return_address);
|
||||||
#if !defined(_MSC_VER) || !defined(NDEBUG)
|
# if !defined(_MSC_VER) || !defined(NDEBUG)
|
||||||
CHECK(symbol != nullptr);
|
CHECK(symbol != nullptr);
|
||||||
CHECK_STREQ(symbol, "main");
|
CHECK_STREQ(symbol, "main");
|
||||||
#endif
|
# endif
|
||||||
cout << "Test case TestWithReturnAddress passed." << endl;
|
cout << "Test case TestWithReturnAddress passed." << endl;
|
||||||
}
|
}
|
||||||
# endif // __ELF__
|
# endif // __ELF__
|
||||||
#endif // HAVE_STACKTRACE
|
#endif // HAVE_STACKTRACE
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char** argv) {
|
||||||
FLAGS_logtostderr = true;
|
FLAGS_logtostderr = true;
|
||||||
InitGoogleLogging(argv[0]);
|
InitGoogleLogging(argv[0]);
|
||||||
InitGoogleTest(&argc, argv);
|
InitGoogleTest(&argc, argv);
|
||||||
#if defined(HAVE_SYMBOLIZE) && defined(HAVE_STACKTRACE)
|
#if defined(HAVE_SYMBOLIZE) && defined(HAVE_STACKTRACE)
|
||||||
# if defined(__ELF__)
|
# if defined(__ELF__)
|
||||||
// We don't want to get affected by the callback interface, that may be
|
// We don't want to get affected by the callback interface, that may be
|
||||||
// used to install some callback function at InitGoogle() time.
|
// used to install some callback function at InitGoogle() time.
|
||||||
InstallSymbolizeCallback(nullptr);
|
InstallSymbolizeCallback(nullptr);
|
||||||
@ -449,13 +449,13 @@ int main(int argc, char **argv) {
|
|||||||
TestWithPCInsideNonInlineFunction();
|
TestWithPCInsideNonInlineFunction();
|
||||||
TestWithReturnAddress();
|
TestWithReturnAddress();
|
||||||
return RUN_ALL_TESTS();
|
return RUN_ALL_TESTS();
|
||||||
# elif defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)
|
# elif defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)
|
||||||
TestWithReturnAddress();
|
TestWithReturnAddress();
|
||||||
return RUN_ALL_TESTS();
|
return RUN_ALL_TESTS();
|
||||||
# else // GLOG_OS_WINDOWS
|
# else // GLOG_OS_WINDOWS
|
||||||
printf("PASS (no symbolize_unittest support)\n");
|
printf("PASS (no symbolize_unittest support)\n");
|
||||||
return 0;
|
return 0;
|
||||||
# endif // __ELF__
|
# endif // __ELF__
|
||||||
#else
|
#else
|
||||||
printf("PASS (no symbolize support)\n");
|
printf("PASS (no symbolize support)\n");
|
||||||
return 0;
|
return 0;
|
||||||
@ -463,5 +463,5 @@ int main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__GNUG__)
|
#if defined(__GNUG__)
|
||||||
#pragma GCC diagnostic pop
|
# pragma GCC diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
156
src/utilities.cc
156
src/utilities.cc
@ -29,33 +29,33 @@
|
|||||||
//
|
//
|
||||||
// Author: Shinichiro Hamaji
|
// Author: Shinichiro Hamaji
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
|
||||||
|
#include <csignal>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
#include <csignal>
|
#include "config.h"
|
||||||
#ifdef HAVE_SYS_TIME_H
|
#ifdef HAVE_SYS_TIME_H
|
||||||
# include <sys/time.h>
|
# include <sys/time.h>
|
||||||
#endif
|
#endif
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#if defined(HAVE_SYSCALL_H)
|
#if defined(HAVE_SYSCALL_H)
|
||||||
#include <syscall.h> // for syscall()
|
# include <syscall.h> // for syscall()
|
||||||
#elif defined(HAVE_SYS_SYSCALL_H)
|
#elif defined(HAVE_SYS_SYSCALL_H)
|
||||||
#include <sys/syscall.h> // for syscall()
|
# include <sys/syscall.h> // for syscall()
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_SYSLOG_H
|
#ifdef HAVE_SYSLOG_H
|
||||||
# include <syslog.h>
|
# include <syslog.h>
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
# include <unistd.h> // For geteuid.
|
# include <unistd.h> // For geteuid.
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_PWD_H
|
#ifdef HAVE_PWD_H
|
||||||
# include <pwd.h>
|
# include <pwd.h>
|
||||||
#endif
|
#endif
|
||||||
#ifdef __ANDROID__
|
#ifdef __ANDROID__
|
||||||
#include <android/log.h>
|
# include <android/log.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "base/googleinit.h"
|
#include "base/googleinit.h"
|
||||||
@ -75,9 +75,9 @@ bool IsGoogleLoggingInitialized() {
|
|||||||
// The following APIs are all internal.
|
// The following APIs are all internal.
|
||||||
#ifdef HAVE_STACKTRACE
|
#ifdef HAVE_STACKTRACE
|
||||||
|
|
||||||
#include "stacktrace.h"
|
# include "base/commandlineflags.h"
|
||||||
#include "symbolize.h"
|
# include "stacktrace.h"
|
||||||
#include "base/commandlineflags.h"
|
# include "symbolize.h"
|
||||||
|
|
||||||
GLOG_DEFINE_bool(symbolize_stacktrace, true,
|
GLOG_DEFINE_bool(symbolize_stacktrace, true,
|
||||||
"Symbolize the stack trace in the tombstone");
|
"Symbolize the stack trace in the tombstone");
|
||||||
@ -90,44 +90,44 @@ using DebugWriter = void(const char*, void*);
|
|||||||
// For some environments, add two extra bytes for the leading "0x".
|
// For some environments, add two extra bytes for the leading "0x".
|
||||||
static const int kPrintfPointerFieldWidth = 2 + 2 * sizeof(void*);
|
static const int kPrintfPointerFieldWidth = 2 + 2 * sizeof(void*);
|
||||||
|
|
||||||
static void DebugWriteToStderr(const char* data, void *) {
|
static void DebugWriteToStderr(const char* data, void*) {
|
||||||
// This one is signal-safe.
|
// This one is signal-safe.
|
||||||
if (write(STDERR_FILENO, data, strlen(data)) < 0) {
|
if (write(STDERR_FILENO, data, strlen(data)) < 0) {
|
||||||
// Ignore errors.
|
// Ignore errors.
|
||||||
}
|
}
|
||||||
#if defined(__ANDROID__)
|
# if defined(__ANDROID__)
|
||||||
// ANDROID_LOG_FATAL as fatal error occurred and now is dumping call stack.
|
// ANDROID_LOG_FATAL as fatal error occurred and now is dumping call stack.
|
||||||
__android_log_write(ANDROID_LOG_FATAL,
|
__android_log_write(ANDROID_LOG_FATAL,
|
||||||
glog_internal_namespace_::ProgramInvocationShortName(),
|
glog_internal_namespace_::ProgramInvocationShortName(),
|
||||||
data);
|
data);
|
||||||
#endif
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DebugWriteToString(const char* data, void *arg) {
|
static void DebugWriteToString(const char* data, void* arg) {
|
||||||
reinterpret_cast<string*>(arg)->append(data);
|
reinterpret_cast<string*>(arg)->append(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_SYMBOLIZE
|
# ifdef HAVE_SYMBOLIZE
|
||||||
// Print a program counter and its symbol name.
|
// Print a program counter and its symbol name.
|
||||||
static void DumpPCAndSymbol(DebugWriter *writerfn, void *arg, void *pc,
|
static void DumpPCAndSymbol(DebugWriter* writerfn, void* arg, void* pc,
|
||||||
const char * const prefix) {
|
const char* const prefix) {
|
||||||
char tmp[1024];
|
char tmp[1024];
|
||||||
const char *symbol = "(unknown)";
|
const char* symbol = "(unknown)";
|
||||||
// Symbolizes the previous address of pc because pc may be in the
|
// Symbolizes the previous address of pc because pc may be in the
|
||||||
// next function. The overrun happens when the function ends with
|
// next function. The overrun happens when the function ends with
|
||||||
// a call to a function annotated noreturn (e.g. CHECK).
|
// a call to a function annotated noreturn (e.g. CHECK).
|
||||||
if (Symbolize(reinterpret_cast<char *>(pc) - 1, tmp, sizeof(tmp))) {
|
if (Symbolize(reinterpret_cast<char*>(pc) - 1, tmp, sizeof(tmp))) {
|
||||||
symbol = tmp;
|
symbol = tmp;
|
||||||
}
|
}
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
std::snprintf(buf, sizeof(buf), "%s@ %*p %s\n", prefix,
|
std::snprintf(buf, sizeof(buf), "%s@ %*p %s\n", prefix,
|
||||||
kPrintfPointerFieldWidth, pc, symbol);
|
kPrintfPointerFieldWidth, pc, symbol);
|
||||||
writerfn(buf, arg);
|
writerfn(buf, arg);
|
||||||
}
|
}
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
static void DumpPC(DebugWriter *writerfn, void *arg, void *pc,
|
static void DumpPC(DebugWriter* writerfn, void* arg, void* pc,
|
||||||
const char * const prefix) {
|
const char* const prefix) {
|
||||||
char buf[100];
|
char buf[100];
|
||||||
std::snprintf(buf, sizeof(buf), "%s@ %*p\n", prefix, kPrintfPointerFieldWidth,
|
std::snprintf(buf, sizeof(buf), "%s@ %*p\n", prefix, kPrintfPointerFieldWidth,
|
||||||
pc);
|
pc);
|
||||||
@ -135,26 +135,26 @@ static void DumpPC(DebugWriter *writerfn, void *arg, void *pc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Dump current stack trace as directed by writerfn
|
// Dump current stack trace as directed by writerfn
|
||||||
static void DumpStackTrace(int skip_count, DebugWriter *writerfn, void *arg) {
|
static void DumpStackTrace(int skip_count, DebugWriter* writerfn, void* arg) {
|
||||||
// Print stack trace
|
// Print stack trace
|
||||||
void* stack[32];
|
void* stack[32];
|
||||||
int depth = GetStackTrace(stack, ARRAYSIZE(stack), skip_count+1);
|
int depth = GetStackTrace(stack, ARRAYSIZE(stack), skip_count + 1);
|
||||||
for (int i = 0; i < depth; i++) {
|
for (int i = 0; i < depth; i++) {
|
||||||
#if defined(HAVE_SYMBOLIZE)
|
# if defined(HAVE_SYMBOLIZE)
|
||||||
if (FLAGS_symbolize_stacktrace) {
|
if (FLAGS_symbolize_stacktrace) {
|
||||||
DumpPCAndSymbol(writerfn, arg, stack[i], " ");
|
DumpPCAndSymbol(writerfn, arg, stack[i], " ");
|
||||||
} else {
|
} else {
|
||||||
DumpPC(writerfn, arg, stack[i], " ");
|
DumpPC(writerfn, arg, stack[i], " ");
|
||||||
}
|
}
|
||||||
#else
|
# else
|
||||||
DumpPC(writerfn, arg, stack[i], " ");
|
DumpPC(writerfn, arg, stack[i], " ");
|
||||||
#endif
|
# endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __GNUC__
|
# ifdef __GNUC__
|
||||||
__attribute__((noreturn))
|
__attribute__((noreturn))
|
||||||
#endif
|
# endif
|
||||||
static void
|
static void
|
||||||
DumpStackTraceAndExit() {
|
DumpStackTraceAndExit() {
|
||||||
DumpStackTrace(1, DebugWriteToStderr, nullptr);
|
DumpStackTrace(1, DebugWriteToStderr, nullptr);
|
||||||
@ -163,15 +163,15 @@ DumpStackTraceAndExit() {
|
|||||||
if (IsFailureSignalHandlerInstalled()) {
|
if (IsFailureSignalHandlerInstalled()) {
|
||||||
// Set the default signal handler for SIGABRT, to avoid invoking our
|
// Set the default signal handler for SIGABRT, to avoid invoking our
|
||||||
// own signal handler installed by InstallFailureSignalHandler().
|
// own signal handler installed by InstallFailureSignalHandler().
|
||||||
#ifdef HAVE_SIGACTION
|
# ifdef HAVE_SIGACTION
|
||||||
struct sigaction sig_action;
|
struct sigaction sig_action;
|
||||||
memset(&sig_action, 0, sizeof(sig_action));
|
memset(&sig_action, 0, sizeof(sig_action));
|
||||||
sigemptyset(&sig_action.sa_mask);
|
sigemptyset(&sig_action.sa_mask);
|
||||||
sig_action.sa_handler = SIG_DFL;
|
sig_action.sa_handler = SIG_DFL;
|
||||||
sigaction(SIGABRT, &sig_action, nullptr);
|
sigaction(SIGABRT, &sig_action, nullptr);
|
||||||
#elif defined(GLOG_OS_WINDOWS)
|
# elif defined(GLOG_OS_WINDOWS)
|
||||||
signal(SIGABRT, SIG_DFL);
|
signal(SIGABRT, SIG_DFL);
|
||||||
#endif // HAVE_SIGACTION
|
# endif // HAVE_SIGACTION
|
||||||
}
|
}
|
||||||
|
|
||||||
abort();
|
abort();
|
||||||
@ -199,14 +199,15 @@ struct timeval {
|
|||||||
long tv_sec, tv_usec;
|
long tv_sec, tv_usec;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Based on: http://www.google.com/codesearch/p?hl=en#dR3YEbitojA/os_win32.c&q=GetSystemTimeAsFileTime%20license:bsd
|
// Based on:
|
||||||
|
// http://www.google.com/codesearch/p?hl=en#dR3YEbitojA/os_win32.c&q=GetSystemTimeAsFileTime%20license:bsd
|
||||||
// See COPYING for copyright information.
|
// See COPYING for copyright information.
|
||||||
static int gettimeofday(struct timeval *tv, void* /*tz*/) {
|
static int gettimeofday(struct timeval* tv, void* /*tz*/) {
|
||||||
#ifdef __GNUC__
|
# ifdef __GNUC__
|
||||||
#pragma GCC diagnostic push
|
# pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wlong-long"
|
# pragma GCC diagnostic ignored "-Wlong-long"
|
||||||
#endif
|
# endif
|
||||||
#define EPOCHFILETIME (116444736000000000ULL)
|
# define EPOCHFILETIME (116444736000000000ULL)
|
||||||
FILETIME ft;
|
FILETIME ft;
|
||||||
ULARGE_INTEGER li;
|
ULARGE_INTEGER li;
|
||||||
uint64 tt;
|
uint64 tt;
|
||||||
@ -217,9 +218,9 @@ static int gettimeofday(struct timeval *tv, void* /*tz*/) {
|
|||||||
tt = (li.QuadPart - EPOCHFILETIME) / 10;
|
tt = (li.QuadPart - EPOCHFILETIME) / 10;
|
||||||
tv->tv_sec = tt / 1000000;
|
tv->tv_sec = tt / 1000000;
|
||||||
tv->tv_usec = tt % 1000000;
|
tv->tv_usec = tt % 1000000;
|
||||||
#ifdef __GNUC__
|
# ifdef __GNUC__
|
||||||
#pragma GCC diagnostic pop
|
# pragma GCC diagnostic pop
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -232,9 +233,7 @@ int64 CycleClock_Now() {
|
|||||||
return static_cast<int64>(tv.tv_sec) * 1000000 + tv.tv_usec;
|
return static_cast<int64>(tv.tv_sec) * 1000000 + tv.tv_usec;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64 UsecToCycles(int64 usec) {
|
int64 UsecToCycles(int64 usec) { return usec; }
|
||||||
return usec;
|
|
||||||
}
|
|
||||||
|
|
||||||
WallTime WallTime_Now() {
|
WallTime WallTime_Now() {
|
||||||
// Now, cycle clock is retuning microseconds since the epoch.
|
// Now, cycle clock is retuning microseconds since the epoch.
|
||||||
@ -242,9 +241,7 @@ WallTime WallTime_Now() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int32 g_main_thread_pid = getpid();
|
static int32 g_main_thread_pid = getpid();
|
||||||
int32 GetMainThreadPid() {
|
int32 GetMainThreadPid() { return g_main_thread_pid; }
|
||||||
return g_main_thread_pid;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PidHasChanged() {
|
bool PidHasChanged() {
|
||||||
int32 pid = getpid();
|
int32 pid = getpid();
|
||||||
@ -258,24 +255,24 @@ bool PidHasChanged() {
|
|||||||
pid_t GetTID() {
|
pid_t GetTID() {
|
||||||
// On Linux and MacOSX, we try to use gettid().
|
// On Linux and MacOSX, we try to use gettid().
|
||||||
#if defined GLOG_OS_LINUX || defined GLOG_OS_MACOSX
|
#if defined GLOG_OS_LINUX || defined GLOG_OS_MACOSX
|
||||||
#ifndef __NR_gettid
|
# ifndef __NR_gettid
|
||||||
#ifdef GLOG_OS_MACOSX
|
# ifdef GLOG_OS_MACOSX
|
||||||
#define __NR_gettid SYS_gettid
|
# define __NR_gettid SYS_gettid
|
||||||
#elif ! defined __i386__
|
# elif !defined __i386__
|
||||||
#error "Must define __NR_gettid for non-x86 platforms"
|
# error "Must define __NR_gettid for non-x86 platforms"
|
||||||
#else
|
# else
|
||||||
#define __NR_gettid 224
|
# define __NR_gettid 224
|
||||||
#endif
|
# endif
|
||||||
#endif
|
# endif
|
||||||
static bool lacks_gettid = false;
|
static bool lacks_gettid = false;
|
||||||
if (!lacks_gettid) {
|
if (!lacks_gettid) {
|
||||||
#if (defined(GLOG_OS_MACOSX) && defined(HAVE_PTHREAD_THREADID_NP))
|
# if (defined(GLOG_OS_MACOSX) && defined(HAVE_PTHREAD_THREADID_NP))
|
||||||
uint64_t tid64;
|
uint64_t tid64;
|
||||||
const int error = pthread_threadid_np(nullptr, &tid64);
|
const int error = pthread_threadid_np(nullptr, &tid64);
|
||||||
pid_t tid = error ? -1 : static_cast<pid_t>(tid64);
|
pid_t tid = error ? -1 : static_cast<pid_t>(tid64);
|
||||||
#else
|
# else
|
||||||
auto tid = static_cast<pid_t>(syscall(__NR_gettid));
|
auto tid = static_cast<pid_t>(syscall(__NR_gettid));
|
||||||
#endif
|
# endif
|
||||||
if (tid != -1) {
|
if (tid != -1) {
|
||||||
return tid;
|
return tid;
|
||||||
}
|
}
|
||||||
@ -305,16 +302,13 @@ pid_t GetTID() {
|
|||||||
const char* const_basename(const char* filepath) {
|
const char* const_basename(const char* filepath) {
|
||||||
const char* base = strrchr(filepath, '/');
|
const char* base = strrchr(filepath, '/');
|
||||||
#ifdef GLOG_OS_WINDOWS // Look for either path separator in Windows
|
#ifdef GLOG_OS_WINDOWS // Look for either path separator in Windows
|
||||||
if (!base)
|
if (!base) base = strrchr(filepath, '\\');
|
||||||
base = strrchr(filepath, '\\');
|
|
||||||
#endif
|
#endif
|
||||||
return base ? (base+1) : filepath;
|
return base ? (base + 1) : filepath;
|
||||||
}
|
}
|
||||||
|
|
||||||
static string g_my_user_name;
|
static string g_my_user_name;
|
||||||
const string& MyUserName() {
|
const string& MyUserName() { return g_my_user_name; }
|
||||||
return g_my_user_name;
|
|
||||||
}
|
|
||||||
static void MyUserNameInitializer() {
|
static void MyUserNameInitializer() {
|
||||||
// TODO(hamaji): Probably this is not portable.
|
// TODO(hamaji): Probably this is not portable.
|
||||||
#if defined(GLOG_OS_WINDOWS)
|
#if defined(GLOG_OS_WINDOWS)
|
||||||
@ -356,8 +350,7 @@ void DumpStackTraceToString(string* stacktrace) {
|
|||||||
static const CrashReason* g_reason = nullptr;
|
static const CrashReason* g_reason = nullptr;
|
||||||
|
|
||||||
void SetCrashReason(const CrashReason* r) {
|
void SetCrashReason(const CrashReason* r) {
|
||||||
sync_val_compare_and_swap(&g_reason,
|
sync_val_compare_and_swap(&g_reason, reinterpret_cast<const CrashReason*>(0),
|
||||||
reinterpret_cast<const CrashReason*>(0),
|
|
||||||
r);
|
r);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -366,7 +359,7 @@ void InitGoogleLoggingUtilities(const char* argv0) {
|
|||||||
<< "You called InitGoogleLogging() twice!";
|
<< "You called InitGoogleLogging() twice!";
|
||||||
const char* slash = strrchr(argv0, '/');
|
const char* slash = strrchr(argv0, '/');
|
||||||
#ifdef GLOG_OS_WINDOWS
|
#ifdef GLOG_OS_WINDOWS
|
||||||
if (!slash) slash = strrchr(argv0, '\\');
|
if (!slash) slash = strrchr(argv0, '\\');
|
||||||
#endif
|
#endif
|
||||||
g_program_invocation_short_name = slash ? slash + 1 : argv0;
|
g_program_invocation_short_name = slash ? slash + 1 : argv0;
|
||||||
|
|
||||||
@ -377,7 +370,8 @@ void InitGoogleLoggingUtilities(const char* argv0) {
|
|||||||
|
|
||||||
void ShutdownGoogleLoggingUtilities() {
|
void ShutdownGoogleLoggingUtilities() {
|
||||||
CHECK(IsGoogleLoggingInitialized())
|
CHECK(IsGoogleLoggingInitialized())
|
||||||
<< "You called ShutdownGoogleLogging() without calling InitGoogleLogging() first!";
|
<< "You called ShutdownGoogleLogging() without calling "
|
||||||
|
"InitGoogleLogging() first!";
|
||||||
g_program_invocation_short_name = nullptr;
|
g_program_invocation_short_name = nullptr;
|
||||||
#ifdef HAVE_SYSLOG_H
|
#ifdef HAVE_SYSLOG_H
|
||||||
closelog();
|
closelog();
|
||||||
@ -390,13 +384,13 @@ void ShutdownGoogleLoggingUtilities() {
|
|||||||
|
|
||||||
// Make an implementation of stacktrace compiled.
|
// Make an implementation of stacktrace compiled.
|
||||||
#ifdef STACKTRACE_H
|
#ifdef STACKTRACE_H
|
||||||
# include STACKTRACE_H
|
# include STACKTRACE_H
|
||||||
# if 0
|
# if 0
|
||||||
// For include scanners which can't handle macro expansions.
|
// For include scanners which can't handle macro expansions.
|
||||||
# include "stacktrace_libunwind-inl.h"
|
# include "stacktrace_generic-inl.h"
|
||||||
# include "stacktrace_x86-inl.h"
|
# include "stacktrace_libunwind-inl.h"
|
||||||
# include "stacktrace_x86_64-inl.h"
|
# include "stacktrace_powerpc-inl.h"
|
||||||
# include "stacktrace_powerpc-inl.h"
|
# include "stacktrace_x86-inl.h"
|
||||||
# include "stacktrace_generic-inl.h"
|
# include "stacktrace_x86_64-inl.h"
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -36,9 +36,9 @@
|
|||||||
|
|
||||||
// printf macros for size_t, in the style of inttypes.h
|
// printf macros for size_t, in the style of inttypes.h
|
||||||
#ifdef _LP64
|
#ifdef _LP64
|
||||||
#define __PRIS_PREFIX "z"
|
# define __PRIS_PREFIX "z"
|
||||||
#else
|
#else
|
||||||
#define __PRIS_PREFIX
|
# define __PRIS_PREFIX
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Use these macros after a % in a printf format string
|
// Use these macros after a % in a printf format string
|
||||||
@ -58,22 +58,22 @@
|
|||||||
#include "glog/logging.h"
|
#include "glog/logging.h"
|
||||||
|
|
||||||
#if defined(GLOG_OS_WINDOWS)
|
#if defined(GLOG_OS_WINDOWS)
|
||||||
# include "port.h"
|
# include "port.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#if defined(HAVE_UNISTD_H)
|
#if defined(HAVE_UNISTD_H)
|
||||||
#include <unistd.h>
|
# include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(HAVE_SSIZE_T)
|
#if !defined(HAVE_SSIZE_T)
|
||||||
#if defined(GLOG_OS_WINDOWS)
|
# if defined(GLOG_OS_WINDOWS)
|
||||||
#include <basetsd.h>
|
# include <basetsd.h>
|
||||||
using ssize_t = SSIZE_T;
|
using ssize_t = SSIZE_T;
|
||||||
#else
|
# else
|
||||||
using ssize_t = std::ptrdiff_t;
|
using ssize_t = std::ptrdiff_t;
|
||||||
#endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// There are three different ways we can try to get the stack trace:
|
// There are three different ways we can try to get the stack trace:
|
||||||
@ -99,45 +99,45 @@ using ssize_t = std::ptrdiff_t;
|
|||||||
// Some code may do that.
|
// Some code may do that.
|
||||||
|
|
||||||
#if defined(HAVE_LIBUNWIND)
|
#if defined(HAVE_LIBUNWIND)
|
||||||
# define STACKTRACE_H "stacktrace_libunwind-inl.h"
|
# define STACKTRACE_H "stacktrace_libunwind-inl.h"
|
||||||
#elif defined(HAVE_UNWIND)
|
#elif defined(HAVE_UNWIND)
|
||||||
# define STACKTRACE_H "stacktrace_unwind-inl.h"
|
# define STACKTRACE_H "stacktrace_unwind-inl.h"
|
||||||
#elif !defined(NO_FRAME_POINTER)
|
#elif !defined(NO_FRAME_POINTER)
|
||||||
# if defined(__i386__) && __GNUC__ >= 2
|
# if defined(__i386__) && __GNUC__ >= 2
|
||||||
# define STACKTRACE_H "stacktrace_x86-inl.h"
|
# define STACKTRACE_H "stacktrace_x86-inl.h"
|
||||||
# elif (defined(__ppc__) || defined(__PPC__)) && __GNUC__ >= 2
|
# elif (defined(__ppc__) || defined(__PPC__)) && __GNUC__ >= 2
|
||||||
# define STACKTRACE_H "stacktrace_powerpc-inl.h"
|
# define STACKTRACE_H "stacktrace_powerpc-inl.h"
|
||||||
# elif defined(GLOG_OS_WINDOWS)
|
# elif defined(GLOG_OS_WINDOWS)
|
||||||
# define STACKTRACE_H "stacktrace_windows-inl.h"
|
# define STACKTRACE_H "stacktrace_windows-inl.h"
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(STACKTRACE_H) && defined(HAVE_EXECINFO_BACKTRACE)
|
#if !defined(STACKTRACE_H) && defined(HAVE_EXECINFO_BACKTRACE)
|
||||||
# define STACKTRACE_H "stacktrace_generic-inl.h"
|
# define STACKTRACE_H "stacktrace_generic-inl.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(STACKTRACE_H)
|
#if defined(STACKTRACE_H)
|
||||||
# define HAVE_STACKTRACE
|
# define HAVE_STACKTRACE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef GLOG_NO_SYMBOLIZE_DETECTION
|
#ifndef GLOG_NO_SYMBOLIZE_DETECTION
|
||||||
#ifndef HAVE_SYMBOLIZE
|
# ifndef HAVE_SYMBOLIZE
|
||||||
// defined by gcc
|
// defined by gcc
|
||||||
#if defined(__ELF__) && defined(GLOG_OS_LINUX)
|
# if defined(__ELF__) && defined(GLOG_OS_LINUX)
|
||||||
# define HAVE_SYMBOLIZE
|
# define HAVE_SYMBOLIZE
|
||||||
#elif defined(GLOG_OS_MACOSX) && defined(HAVE_DLADDR)
|
# elif defined(GLOG_OS_MACOSX) && defined(HAVE_DLADDR)
|
||||||
// Use dladdr to symbolize.
|
// Use dladdr to symbolize.
|
||||||
# define HAVE_SYMBOLIZE
|
# define HAVE_SYMBOLIZE
|
||||||
#elif defined(GLOG_OS_WINDOWS)
|
# elif defined(GLOG_OS_WINDOWS)
|
||||||
// Use DbgHelp to symbolize
|
// Use DbgHelp to symbolize
|
||||||
# define HAVE_SYMBOLIZE
|
# define HAVE_SYMBOLIZE
|
||||||
#endif
|
# endif
|
||||||
#endif // !defined(HAVE_SYMBOLIZE)
|
# endif // !defined(HAVE_SYMBOLIZE)
|
||||||
#endif // !defined(GLOG_NO_SYMBOLIZE_DETECTION)
|
#endif // !defined(GLOG_NO_SYMBOLIZE_DETECTION)
|
||||||
|
|
||||||
#ifndef ARRAYSIZE
|
#ifndef ARRAYSIZE
|
||||||
// There is a better way, but this is good enough for our purpose.
|
// There is a better way, but this is good enough for our purpose.
|
||||||
# define ARRAYSIZE(a) (sizeof(a) / sizeof(*(a)))
|
# define ARRAYSIZE(a) (sizeof(a) / sizeof(*(a)))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace google {
|
namespace google {
|
||||||
@ -145,21 +145,21 @@ namespace google {
|
|||||||
namespace glog_internal_namespace_ {
|
namespace glog_internal_namespace_ {
|
||||||
|
|
||||||
#if defined(__has_attribute)
|
#if defined(__has_attribute)
|
||||||
#if __has_attribute(noinline)
|
# if __has_attribute(noinline)
|
||||||
# define ATTRIBUTE_NOINLINE __attribute__ ((noinline))
|
# define ATTRIBUTE_NOINLINE __attribute__((noinline))
|
||||||
# define HAVE_ATTRIBUTE_NOINLINE
|
# define HAVE_ATTRIBUTE_NOINLINE
|
||||||
#endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(HAVE_ATTRIBUTE_NOINLINE)
|
#if !defined(HAVE_ATTRIBUTE_NOINLINE)
|
||||||
#if defined(GLOG_OS_WINDOWS)
|
# if defined(GLOG_OS_WINDOWS)
|
||||||
# define ATTRIBUTE_NOINLINE __declspec(noinline)
|
# define ATTRIBUTE_NOINLINE __declspec(noinline)
|
||||||
# define HAVE_ATTRIBUTE_NOINLINE
|
# define HAVE_ATTRIBUTE_NOINLINE
|
||||||
#endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(HAVE_ATTRIBUTE_NOINLINE)
|
#if !defined(HAVE_ATTRIBUTE_NOINLINE)
|
||||||
# define ATTRIBUTE_NOINLINE
|
# define ATTRIBUTE_NOINLINE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const char* ProgramInvocationShortName();
|
const char* ProgramInvocationShortName();
|
||||||
@ -184,20 +184,20 @@ const char* const_basename(const char* filepath);
|
|||||||
// defined, we try the CPU specific logics (we only support x86 and
|
// defined, we try the CPU specific logics (we only support x86 and
|
||||||
// x86_64 for now) first, then use a naive implementation, which has a
|
// x86_64 for now) first, then use a naive implementation, which has a
|
||||||
// race condition.
|
// race condition.
|
||||||
template<typename T>
|
template <typename T>
|
||||||
inline T sync_val_compare_and_swap(T* ptr, T oldval, T newval) {
|
inline T sync_val_compare_and_swap(T* ptr, T oldval, T newval) {
|
||||||
#if defined(HAVE___SYNC_VAL_COMPARE_AND_SWAP)
|
#if defined(HAVE___SYNC_VAL_COMPARE_AND_SWAP)
|
||||||
return __sync_val_compare_and_swap(ptr, oldval, newval);
|
return __sync_val_compare_and_swap(ptr, oldval, newval);
|
||||||
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
|
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
|
||||||
T ret;
|
T ret;
|
||||||
__asm__ __volatile__("lock; cmpxchg %1, (%2);"
|
__asm__ __volatile__("lock; cmpxchg %1, (%2);"
|
||||||
:"=a"(ret)
|
: "=a"(ret)
|
||||||
// GCC may produces %sil or %dil for
|
// GCC may produces %sil or %dil for
|
||||||
// constraint "r", but some of apple's gas
|
// constraint "r", but some of apple's gas
|
||||||
// doesn't know the 8 bit registers.
|
// doesn't know the 8 bit registers.
|
||||||
// We use "q" to avoid these registers.
|
// We use "q" to avoid these registers.
|
||||||
:"q"(newval), "q"(ptr), "a"(oldval)
|
: "q"(newval), "q"(ptr), "a"(oldval)
|
||||||
:"memory", "cc");
|
: "memory", "cc");
|
||||||
return ret;
|
return ret;
|
||||||
#else
|
#else
|
||||||
T ret = *ptr;
|
T ret = *ptr;
|
||||||
|
|||||||
@ -34,7 +34,7 @@
|
|||||||
#include "googletest.h"
|
#include "googletest.h"
|
||||||
|
|
||||||
#ifdef GLOG_USE_GFLAGS
|
#ifdef GLOG_USE_GFLAGS
|
||||||
#include <gflags/gflags.h>
|
# include <gflags/gflags.h>
|
||||||
using namespace GFLAGS_NAMESPACE;
|
using namespace GFLAGS_NAMESPACE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ TEST(utilities, InitGoogleLoggingDeathTest) {
|
|||||||
ASSERT_DEATH(InitGoogleLogging("foobar"), "");
|
ASSERT_DEATH(InitGoogleLogging("foobar"), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char** argv) {
|
||||||
InitGoogleLogging(argv[0]);
|
InitGoogleLogging(argv[0]);
|
||||||
InitGoogleTest(&argc, argv);
|
InitGoogleTest(&argc, argv);
|
||||||
|
|
||||||
|
|||||||
@ -49,14 +49,17 @@
|
|||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
|
|
||||||
GLOG_DEFINE_int32(v, 0, "Show all VLOG(m) messages for m <= this."
|
GLOG_DEFINE_int32(v, 0,
|
||||||
" Overridable by --vmodule.");
|
"Show all VLOG(m) messages for m <= this."
|
||||||
|
" Overridable by --vmodule.");
|
||||||
|
|
||||||
GLOG_DEFINE_string(vmodule, "", "per-module verbose level."
|
GLOG_DEFINE_string(
|
||||||
" Argument is a comma-separated list of <module name>=<log level>."
|
vmodule, "",
|
||||||
" <module name> is a glob pattern, matched against the filename base"
|
"per-module verbose level."
|
||||||
" (that is, name ignoring .cc/.h./-inl.h)."
|
" Argument is a comma-separated list of <module name>=<log level>."
|
||||||
" <log level> overrides any value given by --v.");
|
" <module name> is a glob pattern, matched against the filename base"
|
||||||
|
" (that is, name ignoring .cc/.h./-inl.h)."
|
||||||
|
" <log level> overrides any value given by --v.");
|
||||||
|
|
||||||
namespace google {
|
namespace google {
|
||||||
|
|
||||||
@ -75,18 +78,19 @@ GLOG_EXPORT bool SafeFNMatch_(const char* pattern, size_t patt_len,
|
|||||||
size_t p = 0;
|
size_t p = 0;
|
||||||
size_t s = 0;
|
size_t s = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
if (p == patt_len && s == str_len) return true;
|
if (p == patt_len && s == str_len) return true;
|
||||||
if (p == patt_len) return false;
|
if (p == patt_len) return false;
|
||||||
if (s == str_len) return p+1 == patt_len && pattern[p] == '*';
|
if (s == str_len) return p + 1 == patt_len && pattern[p] == '*';
|
||||||
if (pattern[p] == str[s] || pattern[p] == '?') {
|
if (pattern[p] == str[s] || pattern[p] == '?') {
|
||||||
p += 1;
|
p += 1;
|
||||||
s += 1;
|
s += 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (pattern[p] == '*') {
|
if (pattern[p] == '*') {
|
||||||
if (p+1 == patt_len) return true;
|
if (p + 1 == patt_len) return true;
|
||||||
do {
|
do {
|
||||||
if (SafeFNMatch_(pattern+(p+1), patt_len-(p+1), str+s, str_len-s)) {
|
if (SafeFNMatch_(pattern + (p + 1), patt_len - (p + 1), str + s,
|
||||||
|
str_len - s)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
s += 1;
|
s += 1;
|
||||||
@ -177,10 +181,9 @@ int SetVLOGLevel(const char* module_pattern, int log_level) {
|
|||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
info->vlog_level = log_level;
|
info->vlog_level = log_level;
|
||||||
} else if (!found &&
|
} else if (!found && SafeFNMatch_(info->module_pattern.c_str(),
|
||||||
SafeFNMatch_(info->module_pattern.c_str(),
|
info->module_pattern.size(),
|
||||||
info->module_pattern.size(),
|
module_pattern, pattern_len)) {
|
||||||
module_pattern, pattern_len)) {
|
|
||||||
result = info->vlog_level;
|
result = info->vlog_level;
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
@ -216,8 +219,8 @@ int SetVLOGLevel(const char* module_pattern, int log_level) {
|
|||||||
|
|
||||||
// NOTE: Individual VLOG statements cache the integer log level pointers.
|
// NOTE: Individual VLOG statements cache the integer log level pointers.
|
||||||
// NOTE: This function must not allocate memory or require any locks.
|
// NOTE: This function must not allocate memory or require any locks.
|
||||||
bool InitVLOG3__(SiteFlag* site_flag, int32* level_default,
|
bool InitVLOG3__(SiteFlag* site_flag, int32* level_default, const char* fname,
|
||||||
const char* fname, int32 verbose_level) {
|
int32 verbose_level) {
|
||||||
MutexLock l(&vmodule_lock);
|
MutexLock l(&vmodule_lock);
|
||||||
bool read_vmodule_flag = inited_vmodule;
|
bool read_vmodule_flag = inited_vmodule;
|
||||||
if (!read_vmodule_flag) {
|
if (!read_vmodule_flag) {
|
||||||
@ -240,13 +243,13 @@ bool InitVLOG3__(SiteFlag* site_flag, int32* level_default,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
base = base ? (base+1) : fname;
|
base = base ? (base + 1) : fname;
|
||||||
const char* base_end = strchr(base, '.');
|
const char* base_end = strchr(base, '.');
|
||||||
size_t base_length =
|
size_t base_length =
|
||||||
base_end ? static_cast<size_t>(base_end - base) : strlen(base);
|
base_end ? static_cast<size_t>(base_end - base) : strlen(base);
|
||||||
|
|
||||||
// Trim out trailing "-inl" if any
|
// Trim out trailing "-inl" if any
|
||||||
if (base_length >= 4 && (memcmp(base+base_length-4, "-inl", 4) == 0)) {
|
if (base_length >= 4 && (memcmp(base + base_length - 4, "-inl", 4) == 0)) {
|
||||||
base_length -= 4;
|
base_length -= 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,8 +263,8 @@ bool InitVLOG3__(SiteFlag* site_flag, int32* level_default,
|
|||||||
if (SafeFNMatch_(info->module_pattern.c_str(), info->module_pattern.size(),
|
if (SafeFNMatch_(info->module_pattern.c_str(), info->module_pattern.size(),
|
||||||
base, base_length)) {
|
base, base_length)) {
|
||||||
site_flag_value = &info->vlog_level;
|
site_flag_value = &info->vlog_level;
|
||||||
// value at info->vlog_level is now what controls
|
// value at info->vlog_level is now what controls
|
||||||
// the VLOG at the caller site forever
|
// the VLOG at the caller site forever
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1355
src/windows/dirent.h
1355
src/windows/dirent.h
File diff suppressed because it is too large
Load Diff
@ -33,7 +33,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
# error You should only be including windows/port.cc in a windows environment!
|
# error You should only be including windows/port.cc in a windows environment!
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "port.h"
|
#include "port.h"
|
||||||
@ -47,7 +47,7 @@ struct tm* localtime_r(const std::time_t* timep, std::tm* result) {
|
|||||||
localtime_s(result, timep);
|
localtime_s(result, timep);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
#endif // not HAVE_LOCALTIME_R
|
#endif // not HAVE_LOCALTIME_R
|
||||||
#ifndef HAVE_GMTIME_R
|
#ifndef HAVE_GMTIME_R
|
||||||
struct tm* gmtime_r(const std::time_t* timep, std::tm* result) {
|
struct tm* gmtime_r(const std::time_t* timep, std::tm* result) {
|
||||||
gmtime_s(result, timep);
|
gmtime_s(result, timep);
|
||||||
|
|||||||
@ -45,26 +45,26 @@
|
|||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
#ifndef WIN32_LEAN_AND_MEAN
|
# ifndef WIN32_LEAN_AND_MEAN
|
||||||
#define WIN32_LEAN_AND_MEAN /* We always want minimal includes */
|
# define WIN32_LEAN_AND_MEAN /* We always want minimal includes */
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
#include <direct.h> /* for _getcwd() */
|
# include <direct.h> /* for _getcwd() */
|
||||||
#include <io.h> /* because we so often use open/close/etc */
|
# include <io.h> /* because we so often use open/close/etc */
|
||||||
#include <process.h> /* for _getpid() */
|
# include <process.h> /* for _getpid() */
|
||||||
#include <windows.h>
|
# include <windows.h>
|
||||||
#include <winsock.h> /* for gethostname */
|
# include <winsock.h> /* for gethostname */
|
||||||
|
|
||||||
#include <cstdarg> /* template_dictionary.cc uses va_copy */
|
# include <cstdarg> /* template_dictionary.cc uses va_copy */
|
||||||
#include <cstring> /* for _strnicmp(), strerror_s() */
|
# include <cstring> /* for _strnicmp(), strerror_s() */
|
||||||
#include <ctime> /* for localtime_s() */
|
# include <ctime> /* for localtime_s() */
|
||||||
/* Note: the C++ #includes are all together at the bottom. This file is
|
/* Note: the C++ #includes are all together at the bottom. This file is
|
||||||
* used by both C and C++ code, so we put all the C++ together.
|
* used by both C and C++ code, so we put all the C++ together.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "glog/logging.h"
|
# include "glog/logging.h"
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
# ifdef _MSC_VER
|
||||||
|
|
||||||
/* 4244: otherwise we get problems when substracting two size_t's to an int
|
/* 4244: otherwise we get problems when substracting two size_t's to an int
|
||||||
* 4251: it's complaining about a private struct I've chosen not to dllexport
|
* 4251: it's complaining about a private struct I've chosen not to dllexport
|
||||||
@ -76,84 +76,85 @@
|
|||||||
* 4267: also subtracting two size_t to int
|
* 4267: also subtracting two size_t to int
|
||||||
* 4722: Destructor never returns due to abort()
|
* 4722: Destructor never returns due to abort()
|
||||||
*/
|
*/
|
||||||
#pragma warning(disable:4244 4251 4355 4715 4800 4996 4267 4312 4722)
|
# pragma warning(disable : 4244 4251 4355 4715 4800 4996 4267 4312 4722)
|
||||||
|
|
||||||
/* file I/O */
|
/* file I/O */
|
||||||
#define PATH_MAX 1024
|
# define PATH_MAX 1024
|
||||||
#define popen _popen
|
# define popen _popen
|
||||||
#define pclose _pclose
|
# define pclose _pclose
|
||||||
#define R_OK 04 /* read-only (for access()) */
|
# define R_OK 04 /* read-only (for access()) */
|
||||||
#define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR)
|
# define S_ISDIR(m) (((m)&_S_IFMT) == _S_IFDIR)
|
||||||
|
|
||||||
#define O_WRONLY _O_WRONLY
|
# define O_WRONLY _O_WRONLY
|
||||||
#define O_CREAT _O_CREAT
|
# define O_CREAT _O_CREAT
|
||||||
#define O_EXCL _O_EXCL
|
# define O_EXCL _O_EXCL
|
||||||
|
|
||||||
#ifndef __MINGW32__
|
# ifndef __MINGW32__
|
||||||
enum { STDIN_FILENO = 0, STDOUT_FILENO = 1, STDERR_FILENO = 2 };
|
enum { STDIN_FILENO = 0, STDOUT_FILENO = 1, STDERR_FILENO = 2 };
|
||||||
#endif
|
# endif
|
||||||
#define S_IRUSR S_IREAD
|
# define S_IRUSR S_IREAD
|
||||||
#define S_IWUSR S_IWRITE
|
# define S_IWUSR S_IWRITE
|
||||||
|
|
||||||
/* Not quite as lightweight as a hard-link, but more than good enough for us. */
|
/* Not quite as lightweight as a hard-link, but more than good enough for us. */
|
||||||
#define link(oldpath, newpath) CopyFileA(oldpath, newpath, false)
|
# define link(oldpath, newpath) CopyFileA(oldpath, newpath, false)
|
||||||
|
|
||||||
#define strcasecmp _stricmp
|
# define strcasecmp _stricmp
|
||||||
#define strncasecmp _strnicmp
|
# define strncasecmp _strnicmp
|
||||||
|
|
||||||
/* In windows-land, hash<> is called hash_compare<> (from xhash.h) */
|
/* In windows-land, hash<> is called hash_compare<> (from xhash.h) */
|
||||||
/* VC11 provides std::hash */
|
/* VC11 provides std::hash */
|
||||||
#if defined(_MSC_VER) && (_MSC_VER < 1700)
|
# if defined(_MSC_VER) && (_MSC_VER < 1700)
|
||||||
#define hash hash_compare
|
# define hash hash_compare
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
/* Sleep is in ms, on windows */
|
/* Sleep is in ms, on windows */
|
||||||
#define sleep(secs) Sleep((secs) * 1000)
|
# define sleep(secs) Sleep((secs)*1000)
|
||||||
|
|
||||||
/* Windows doesn't support specifying the number of buckets as a
|
/* Windows doesn't support specifying the number of buckets as a
|
||||||
* hash_map constructor arg, so we leave this blank.
|
* hash_map constructor arg, so we leave this blank.
|
||||||
*/
|
*/
|
||||||
#define CTEMPLATE_SMALL_HASHTABLE
|
# define CTEMPLATE_SMALL_HASHTABLE
|
||||||
|
|
||||||
#define DEFAULT_TEMPLATE_ROOTDIR ".."
|
# define DEFAULT_TEMPLATE_ROOTDIR ".."
|
||||||
|
|
||||||
// ----------------------------------- SYSTEM/PROCESS
|
// ----------------------------------- SYSTEM/PROCESS
|
||||||
typedef int pid_t;
|
typedef int pid_t;
|
||||||
#define getpid _getpid
|
# define getpid _getpid
|
||||||
|
|
||||||
#endif // _MSC_VER
|
# endif // _MSC_VER
|
||||||
|
|
||||||
// ----------------------------------- THREADS
|
// ----------------------------------- THREADS
|
||||||
#if defined(HAVE_PTHREAD)
|
# if defined(HAVE_PTHREAD)
|
||||||
# include <pthread.h>
|
# include <pthread.h>
|
||||||
#else // no PTHREAD
|
# else // no PTHREAD
|
||||||
typedef DWORD pthread_t;
|
typedef DWORD pthread_t;
|
||||||
typedef DWORD pthread_key_t;
|
typedef DWORD pthread_key_t;
|
||||||
typedef LONG pthread_once_t;
|
typedef LONG pthread_once_t;
|
||||||
enum { PTHREAD_ONCE_INIT = 0 }; // important that this be 0! for SpinLock
|
enum { PTHREAD_ONCE_INIT = 0 }; // important that this be 0! for SpinLock
|
||||||
#define pthread_self GetCurrentThreadId
|
# define pthread_self GetCurrentThreadId
|
||||||
#define pthread_equal(pthread_t_1, pthread_t_2) ((pthread_t_1)==(pthread_t_2))
|
# define pthread_equal(pthread_t_1, pthread_t_2) \
|
||||||
#endif // HAVE_PTHREAD
|
((pthread_t_1) == (pthread_t_2))
|
||||||
|
# endif // HAVE_PTHREAD
|
||||||
|
|
||||||
#ifndef HAVE_LOCALTIME_R
|
# ifndef HAVE_LOCALTIME_R
|
||||||
extern GLOG_EXPORT std::tm* localtime_r(const std::time_t* timep,
|
extern GLOG_EXPORT std::tm* localtime_r(const std::time_t* timep,
|
||||||
std::tm* result);
|
std::tm* result);
|
||||||
#endif // not HAVE_LOCALTIME_R
|
# endif // not HAVE_LOCALTIME_R
|
||||||
|
|
||||||
#ifndef HAVE_GMTIME_R
|
# ifndef HAVE_GMTIME_R
|
||||||
extern GLOG_EXPORT std::tm* gmtime_r(const std::time_t* timep, std::tm* result);
|
extern GLOG_EXPORT std::tm* gmtime_r(const std::time_t* timep, std::tm* result);
|
||||||
#endif // not HAVE_GMTIME_R
|
# endif // not HAVE_GMTIME_R
|
||||||
|
|
||||||
inline char* strerror_r(int errnum, char* buf, std::size_t buflen) {
|
inline char* strerror_r(int errnum, char* buf, std::size_t buflen) {
|
||||||
strerror_s(buf, buflen, errnum);
|
strerror_s(buf, buflen, errnum);
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef __cplusplus
|
# ifndef __cplusplus
|
||||||
/* I don't see how to get inlining for C code in MSVC. Ah well. */
|
/* I don't see how to get inlining for C code in MSVC. Ah well. */
|
||||||
#define inline
|
# define inline
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
#endif /* _WIN32 */
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
#endif /* CTEMPLATE_WINDOWS_PORT_H_ */
|
#endif /* CTEMPLATE_WINDOWS_PORT_H_ */
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user