Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "absl/debugging/internal/stack_consumption.h"
00017
00018 #ifdef ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION
00019
00020 #include <signal.h>
00021 #include <sys/mman.h>
00022 #include <unistd.h>
00023
00024 #include <string.h>
00025
00026 #include "absl/base/attributes.h"
00027 #include "absl/base/internal/raw_logging.h"
00028
00029 namespace absl {
00030 namespace debugging_internal {
00031 namespace {
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044 #if defined(__i386__) || defined(__x86_64__) || defined(__ppc__)
00045 constexpr bool kStackGrowsDown = true;
00046 #else
00047 #error Need to define kStackGrowsDown
00048 #endif
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064 void EmptySignalHandler(int) {}
00065
00066
00067
00068 constexpr int kAlternateStackSize = 64 << 10;
00069
00070 constexpr int kSafetyMargin = 32;
00071 constexpr char kAlternateStackFillValue = 0x55;
00072
00073
00074
00075
00076
00077
00078
00079 int GetStackConsumption(const void* const altstack) {
00080 const char* begin;
00081 int increment;
00082 if (kStackGrowsDown) {
00083 begin = reinterpret_cast<const char*>(altstack);
00084 increment = 1;
00085 } else {
00086 begin = reinterpret_cast<const char*>(altstack) + kAlternateStackSize - 1;
00087 increment = -1;
00088 }
00089
00090 for (int usage_count = kAlternateStackSize; usage_count > 0; --usage_count) {
00091 if (*begin != kAlternateStackFillValue) {
00092 ABSL_RAW_CHECK(usage_count <= kAlternateStackSize - kSafetyMargin,
00093 "Buffer has overflowed or is about to overflow");
00094 return usage_count;
00095 }
00096 begin += increment;
00097 }
00098
00099 ABSL_RAW_LOG(FATAL, "Unreachable code");
00100 return -1;
00101 }
00102
00103 }
00104
00105 int GetSignalHandlerStackConsumption(void (*signal_handler)(int)) {
00106
00107
00108
00109
00110
00111 void* altstack = mmap(nullptr, kAlternateStackSize, PROT_READ | PROT_WRITE,
00112 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
00113 ABSL_RAW_CHECK(altstack != MAP_FAILED, "mmap() failed");
00114
00115
00116 stack_t sigstk;
00117 memset(&sigstk, 0, sizeof(sigstk));
00118 stack_t old_sigstk;
00119 sigstk.ss_sp = altstack;
00120 sigstk.ss_size = kAlternateStackSize;
00121 sigstk.ss_flags = 0;
00122 ABSL_RAW_CHECK(sigaltstack(&sigstk, &old_sigstk) == 0,
00123 "sigaltstack() failed");
00124
00125
00126 struct sigaction sa;
00127 memset(&sa, 0, sizeof(sa));
00128 struct sigaction old_sa1, old_sa2;
00129 sigemptyset(&sa.sa_mask);
00130 sa.sa_flags = SA_ONSTACK;
00131
00132
00133 sa.sa_handler = EmptySignalHandler;
00134 ABSL_RAW_CHECK(sigaction(SIGUSR1, &sa, &old_sa1) == 0, "sigaction() failed");
00135
00136
00137 sa.sa_handler = signal_handler;
00138 ABSL_RAW_CHECK(sigaction(SIGUSR2, &sa, &old_sa2) == 0, "sigaction() failed");
00139
00140
00141
00142
00143
00144 ABSL_RAW_CHECK(kill(getpid(), SIGUSR1) == 0, "kill() failed");
00145
00146 memset(altstack, kAlternateStackFillValue, kAlternateStackSize);
00147 ABSL_RAW_CHECK(kill(getpid(), SIGUSR1) == 0, "kill() failed");
00148 int base_stack_consumption = GetStackConsumption(altstack);
00149
00150
00151 ABSL_RAW_CHECK(kill(getpid(), SIGUSR2) == 0, "kill() failed");
00152 int signal_handler_stack_consumption = GetStackConsumption(altstack);
00153
00154
00155 ABSL_RAW_CHECK(sigaltstack(&old_sigstk, nullptr) == 0,
00156 "sigaltstack() failed");
00157 ABSL_RAW_CHECK(sigaction(SIGUSR1, &old_sa1, nullptr) == 0,
00158 "sigaction() failed");
00159 ABSL_RAW_CHECK(sigaction(SIGUSR2, &old_sa2, nullptr) == 0,
00160 "sigaction() failed");
00161
00162 ABSL_RAW_CHECK(munmap(altstack, kAlternateStackSize) == 0, "munmap() failed");
00163 if (signal_handler_stack_consumption != -1 && base_stack_consumption != -1) {
00164 return signal_handler_stack_consumption - base_stack_consumption;
00165 }
00166 return -1;
00167 }
00168
00169 }
00170 }
00171
00172 #endif // ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION