abi_test.cc
Go to the documentation of this file.
1 /* Copyright (c) 2018, Google Inc.
2  *
3  * Permission to use, copy, modify, and/or distribute this software for any
4  * purpose with or without fee is hereby granted, provided that the above
5  * copyright notice and this permission notice appear in all copies.
6  *
7  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14 
15 #include "abi_test.h"
16 
17 #include <stdarg.h>
18 #include <stdio.h>
19 
20 #include <algorithm>
21 #include <array>
22 
23 #include <openssl/mem.h>
24 #include <openssl/rand.h>
25 #include <openssl/span.h>
26 
27 #if defined(OPENSSL_X86_64) && defined(SUPPORTS_ABI_TEST)
28 #if defined(OPENSSL_LINUX) && defined(BORINGSSL_HAVE_LIBUNWIND)
29 #define SUPPORTS_UNWIND_TEST
30 #define UNW_LOCAL_ONLY
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <libunwind.h>
34 #include <pthread.h>
35 #include <signal.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sys/stat.h>
39 #include <sys/types.h>
40 #include <unistd.h>
41 #elif defined(OPENSSL_WINDOWS)
42 #define SUPPORTS_UNWIND_TEST
44 #include <windows.h>
45 #include <dbghelp.h>
47 #endif
48 #endif // X86_64 && SUPPORTS_ABI_TEST
49 
50 // FIPS mode breaks unwind tests. See https://crbug.com/boringssl/289.
51 #if defined(BORINGSSL_FIPS)
52 #undef SUPPORTS_UNWIND_TEST
53 #endif
54 
55 
56 namespace abi_test {
57 
58 namespace internal {
59 
60 static bool g_unwind_tests_enabled = false;
61 
64  size_t idx = ret.find(',');
65  if (idx == std::string::npos) {
66  return ret + "()";
67  }
68  size_t idx2 = idx + 1;
69  while (idx2 < ret.size() && ret[idx2] == ' ') {
70  idx2++;
71  }
72  while (idx > 0 && ret[idx - 1] == ' ') {
73  idx--;
74  }
75  return ret.substr(0, idx) + "(" + ret.substr(idx2) + ")";
76 }
77 
78 #if defined(SUPPORTS_ABI_TEST)
79 // ForEachMismatch calls |func| for each register where |a| and |b| differ.
80 template <typename Func>
81 static void ForEachMismatch(const CallerState &a, const CallerState &b,
82  const Func &func) {
83 #define CALLER_STATE_REGISTER(type, name) \
84  if (a.name != b.name) { \
85  func(#name); \
86  }
87  LOOP_CALLER_STATE_REGISTERS()
88 #undef CALLER_STATE_REGISTER
89 }
90 
91 // ReadUnwindResult adds the results of the most recent unwind test to |out|.
92 static void ReadUnwindResult(Result *out);
93 
94 crypto_word_t RunTrampoline(Result *out, crypto_word_t func,
95  const crypto_word_t *argv, size_t argc,
96  bool unwind) {
97  CallerState state;
98  RAND_bytes(reinterpret_cast<uint8_t *>(&state), sizeof(state));
99 
100  unwind &= g_unwind_tests_enabled;
101  CallerState state2 = state;
102  crypto_word_t ret = abi_test_trampoline(func, &state2, argv, argc, unwind);
103 #if defined(OPENSSL_X86_64) || defined(OPENSSL_X86)
104  // Query and clear the direction flag early, so negative tests do not
105  // interfere with |malloc|.
106  bool direction_flag = abi_test_get_and_clear_direction_flag();
107 #endif // OPENSSL_X86_64 || OPENSSL_X86
108 
109  *out = Result();
110  ForEachMismatch(state, state2, [&](const char *reg) {
111  out->errors.push_back(std::string(reg) + " was not restored after return");
112  });
113 #if defined(OPENSSL_X86_64) || defined(OPENSSL_X86)
114  // Linux and Windows ABIs for x86 require the direction flag be cleared on
115  // return. (Some OpenSSL assembly preserves it, which is stronger, but we only
116  // require what is specified by the ABI so |CHECK_ABI| works with C compiler
117  // output.)
118  if (direction_flag) {
119  out->errors.emplace_back("Direction flag set after return");
120  }
121 #endif // OPENSSL_X86_64 || OPENSSL_X86
122  if (unwind) {
123  ReadUnwindResult(out);
124  }
125  return ret;
126 }
127 #endif // SUPPORTS_ABI_TEST
128 
129 #if defined(SUPPORTS_UNWIND_TEST)
130 // We test unwind metadata by running the function under test with the trap flag
131 // set. This results in |SIGTRAP| and |EXCEPTION_SINGLE_STEP| on Linux and
132 // Windows, respectively. We hande these and verify libunwind or the Windows
133 // unwind APIs unwind successfully.
134 
135 // IsAncestorStackFrame returns true if |a_sp| is an ancestor stack frame of
136 // |b_sp|.
137 static bool IsAncestorStackFrame(crypto_word_t a_sp, crypto_word_t b_sp) {
138 #if defined(OPENSSL_X86_64)
139  // The stack grows down, so ancestor stack frames have higher addresses.
140  return a_sp > b_sp;
141 #else
142 #error "unknown architecture"
143 #endif
144 }
145 
146 // Implement some string formatting utilties. Ideally we would use |snprintf|,
147 // but this is called in a signal handler and |snprintf| is not async-signal-
148 // safe.
149 
150 #if !defined(OPENSSL_WINDOWS)
151 static std::array<char, DECIMAL_SIZE(crypto_word_t) + 1> WordToDecimal(
152  crypto_word_t v) {
153  std::array<char, DECIMAL_SIZE(crypto_word_t) + 1> ret;
154  size_t len = 0;
155  do {
156  ret[len++] = '0' + v % 10;
157  v /= 10;
158  } while (v != 0);
159  for (size_t i = 0; i < len / 2; i++) {
160  std::swap(ret[i], ret[len - 1 - i]);
161  }
162  ret[len] = '\0';
163  return ret;
164 }
165 #endif // !OPENSSL_WINDOWS
166 
167 static std::array<char, sizeof(crypto_word_t) * 2 + 1> WordToHex(
168  crypto_word_t v) {
169  static const char kHex[] = "0123456789abcdef";
170  std::array<char, sizeof(crypto_word_t) * 2 + 1> ret;
171  for (size_t i = sizeof(crypto_word_t) - 1; i < sizeof(crypto_word_t); i--) {
172  uint8_t b = v & 0xff;
173  v >>= 8;
174  ret[i * 2] = kHex[b >> 4];
175  ret[i * 2 + 1] = kHex[b & 0xf];
176  }
177  ret[sizeof(crypto_word_t) * 2] = '\0';
178  return ret;
179 }
180 
181 static void StrCatSignalSafeImpl(bssl::Span<char> out) {}
182 
183 template <typename... Args>
184 static void StrCatSignalSafeImpl(bssl::Span<char> out, const char *str,
185  Args... args) {
186  OPENSSL_strlcat(out.data(), str, out.size());
187  StrCatSignalSafeImpl(out, args...);
188 }
189 
190 template <typename... Args>
191 static void StrCatSignalSafe(bssl::Span<char> out, Args... args) {
192  if (out.empty()) {
193  return;
194  }
195  out[0] = '\0';
196  StrCatSignalSafeImpl(out, args...);
197 }
198 
199 template <typename... Args>
200 [[noreturn]] static void FatalError(Args... args) {
201  // We cannot use |snprintf| here because it is not async-signal-safe.
202  char buf[512];
203  StrCatSignalSafe(buf, args..., "\n");
204 #if defined(OPENSSL_WINDOWS)
205  HANDLE stderr_handle = GetStdHandle(STD_ERROR_HANDLE);
206  if (stderr_handle != INVALID_HANDLE_VALUE) {
207  DWORD unused;
208  WriteFile(stderr_handle, buf, strlen(buf), &unused, nullptr);
209  }
210 #else
211  write(STDERR_FILENO, buf, strlen(buf));
212 #endif
213  abort();
214 }
215 
216 class UnwindStatus {
217  public:
218  UnwindStatus() : err_(nullptr) {}
219  explicit UnwindStatus(const char *err) : err_(err) {}
220 
221  bool ok() const { return err_ == nullptr; }
222  const char *Error() const { return err_; }
223 
224  private:
225  const char *err_;
226 };
227 
228 template<typename T>
229 class UnwindStatusOr {
230  public:
231  UnwindStatusOr(UnwindStatus status) : status_(status) {
232  assert(!status_.ok());
233  }
234 
235  UnwindStatusOr(const T &value) : status_(UnwindStatus()), value_(value) {}
236 
237  bool ok() const { return status_.ok(); }
238  const char *Error() const { return status_.Error(); }
239 
240  const T &ValueOrDie(const char *msg = "Unexpected error") const {
241  if (!ok()) {
242  FatalError(msg, ": ", Error());
243  }
244  return value_;
245  }
246 
247  private:
248  UnwindStatus status_;
249  T value_;
250 };
251 
252 // UnwindCursor abstracts between libunwind and Windows unwind APIs. It is
253 // async-signal-safe.
254 #if defined(OPENSSL_WINDOWS)
255 class UnwindCursor {
256  public:
257  explicit UnwindCursor(const CONTEXT &ctx) : ctx_(ctx) {
258  starting_ip_ = ctx_.Rip;
259  }
260 
261  crypto_word_t starting_ip() const { return starting_ip_; }
262 
263  // Step unwinds the cursor by one frame. On success, it returns whether there
264  // were more frames to unwind.
265  UnwindStatusOr<bool> Step() {
266  bool is_top = is_top_;
267  is_top_ = false;
268 
269  DWORD64 image_base;
270  RUNTIME_FUNCTION *entry =
271  RtlLookupFunctionEntry(ctx_.Rip, &image_base, nullptr);
272  if (entry == nullptr) {
273  // This is a leaf function. Leaf functions do not touch stack or
274  // callee-saved registers, so they may be unwound by simulating a ret.
275  if (!is_top) {
276  return UnwindStatus("leaf function found below the top frame");
277  }
278  memcpy(&ctx_.Rip, reinterpret_cast<const void *>(ctx_.Rsp),
279  sizeof(ctx_.Rip));
280  ctx_.Rsp += 8;
281  return true;
282  }
283 
284  // This is a frame function. Call into the Windows unwinder.
285  void *handler_data;
286  DWORD64 establisher_frame;
287  RtlVirtualUnwind(UNW_FLAG_NHANDLER, image_base, ctx_.Rip, entry, &ctx_,
288  &handler_data, &establisher_frame, nullptr);
289  return ctx_.Rip != 0;
290  }
291 
292  // GetIP returns the instruction pointer at the current frame.
293  UnwindStatusOr<crypto_word_t> GetIP() { return ctx_.Rip; }
294 
295  // GetSP returns the stack pointer at the current frame.
296  UnwindStatusOr<crypto_word_t> GetSP() { return ctx_.Rsp; }
297 
298  // GetCallerState returns the callee-saved registers at the current frame.
299  UnwindStatusOr<CallerState> GetCallerState() {
300  CallerState state;
301  state.rbx = ctx_.Rbx;
302  state.rbp = ctx_.Rbp;
303  state.rdi = ctx_.Rdi;
304  state.rsi = ctx_.Rsi;
305  state.r12 = ctx_.R12;
306  state.r13 = ctx_.R13;
307  state.r14 = ctx_.R14;
308  state.r15 = ctx_.R15;
309  memcpy(&state.xmm6, &ctx_.Xmm6, sizeof(Reg128));
310  memcpy(&state.xmm7, &ctx_.Xmm7, sizeof(Reg128));
311  memcpy(&state.xmm8, &ctx_.Xmm8, sizeof(Reg128));
312  memcpy(&state.xmm9, &ctx_.Xmm9, sizeof(Reg128));
313  memcpy(&state.xmm10, &ctx_.Xmm10, sizeof(Reg128));
314  memcpy(&state.xmm11, &ctx_.Xmm11, sizeof(Reg128));
315  memcpy(&state.xmm12, &ctx_.Xmm12, sizeof(Reg128));
316  memcpy(&state.xmm13, &ctx_.Xmm13, sizeof(Reg128));
317  memcpy(&state.xmm14, &ctx_.Xmm14, sizeof(Reg128));
318  memcpy(&state.xmm15, &ctx_.Xmm15, sizeof(Reg128));
319  return state;
320  }
321 
322  // ToString returns a human-readable representation of the address the cursor
323  // started at.
324  const char *ToString() {
325  StrCatSignalSafe(starting_ip_buf_, "0x", WordToHex(starting_ip_).data());
326  return starting_ip_buf_;
327  }
328 
329  private:
330  CONTEXT ctx_;
331  crypto_word_t starting_ip_;
332  char starting_ip_buf_[64];
333  bool is_top_ = true;
334 };
335 #else // !OPENSSL_WINDOWS
336 class UnwindCursor {
337  public:
338  explicit UnwindCursor(unw_context_t *ctx) : ctx_(ctx) {
339  int ret = InitAtSignalFrame(&cursor_);
340  if (ret < 0) {
341  FatalError("Error getting unwind context: ", unw_strerror(ret));
342  }
343  starting_ip_ = GetIP().ValueOrDie("Error getting instruction pointer");
344  }
345 
346  // Step unwinds the cursor by one frame. On success, it returns whether there
347  // were more frames to unwind.
348  UnwindStatusOr<bool> Step() {
349  int ret = unw_step(&cursor_);
350  if (ret < 0) {
351  return UNWError(ret);
352  }
353  return ret != 0;
354  }
355 
356  // GetIP returns the instruction pointer at the current frame.
357  UnwindStatusOr<crypto_word_t> GetIP() {
358  crypto_word_t ip;
359  int ret = GetReg(&ip, UNW_REG_IP);
360  if (ret < 0) {
361  return UNWError(ret);
362  }
363  return ip;
364  }
365 
366  // GetSP returns the stack pointer at the current frame.
367  UnwindStatusOr<crypto_word_t> GetSP() {
368  crypto_word_t sp;
369  int ret = GetReg(&sp, UNW_REG_SP);
370  if (ret < 0) {
371  return UNWError(ret);
372  }
373  return sp;
374  }
375 
376  // GetCallerState returns the callee-saved registers at the current frame.
377  UnwindStatusOr<CallerState> GetCallerState() {
378  CallerState state;
379  int ret = 0;
380 #if defined(OPENSSL_X86_64)
381  ret = ret < 0 ? ret : GetReg(&state.rbx, UNW_X86_64_RBX);
382  ret = ret < 0 ? ret : GetReg(&state.rbp, UNW_X86_64_RBP);
383  ret = ret < 0 ? ret : GetReg(&state.r12, UNW_X86_64_R12);
384  ret = ret < 0 ? ret : GetReg(&state.r13, UNW_X86_64_R13);
385  ret = ret < 0 ? ret : GetReg(&state.r14, UNW_X86_64_R14);
386  ret = ret < 0 ? ret : GetReg(&state.r15, UNW_X86_64_R15);
387 #else
388 #error "unknown architecture"
389 #endif
390  if (ret < 0) {
391  return UNWError(ret);
392  }
393  return state;
394  }
395 
396  // ToString returns a human-readable representation of the address the cursor
397  // started at, using debug information if available.
398  const char *ToString() {
399  // Use a new cursor. |cursor_| has already been unwound, and
400  // |unw_get_proc_name| is slow so we do not sample it unconditionally in the
401  // constructor.
402  unw_cursor_t cursor;
403  unw_word_t off;
404  if (InitAtSignalFrame(&cursor) != 0 ||
405  unw_get_proc_name(&cursor, starting_ip_buf_, sizeof(starting_ip_buf_),
406  &off) != 0) {
407  StrCatSignalSafe(starting_ip_buf_, "0x", WordToHex(starting_ip_).data());
408  return starting_ip_buf_;
409  }
410  size_t len = strlen(starting_ip_buf_);
411  // Print the offset in decimal, to match gdb's disassembly output and ease
412  // debugging.
413  StrCatSignalSafe(bssl::Span<char>(starting_ip_buf_).subspan(len), "+",
414  WordToDecimal(off).data(), " (0x",
415  WordToHex(starting_ip_).data(), ")");
416  return starting_ip_buf_;
417  }
418 
419  private:
420  static UnwindStatus UNWError(int ret) {
421  assert(ret < 0);
422  const char *msg = unw_strerror(ret);
423  return UnwindStatus(msg == nullptr ? "unknown error" : msg);
424  }
425 
426  int InitAtSignalFrame(unw_cursor_t *cursor) {
427  // Work around a bug in libunwind which breaks rax and rdx recovery. This
428  // breaks functions which temporarily use rax as the CFA register. See
429  // https://git.savannah.gnu.org/gitweb/?p=libunwind.git;a=commit;h=819bf51bbd2da462c2ec3401e8ac9153b6e725e3
430  OPENSSL_memset(cursor, 0, sizeof(*cursor));
431  int ret = unw_init_local(cursor, ctx_);
432  if (ret < 0) {
433  return ret;
434  }
435  for (;;) {
436  ret = unw_is_signal_frame(cursor);
437  if (ret < 0) {
438  return ret;
439  }
440  if (ret != 0) {
441  return 0; // Found the signal frame.
442  }
443  ret = unw_step(cursor);
444  if (ret < 0) {
445  return ret;
446  }
447  }
448  }
449 
450  int GetReg(crypto_word_t *out, unw_regnum_t reg) {
451  unw_word_t val;
452  int ret = unw_get_reg(&cursor_, reg, &val);
453  if (ret >= 0) {
454  static_assert(sizeof(crypto_word_t) == sizeof(unw_word_t),
455  "crypto_word_t and unw_word_t are inconsistent");
456  *out = val;
457  }
458  return ret;
459  }
460 
461  unw_context_t *ctx_;
462  unw_cursor_t cursor_;
463  crypto_word_t starting_ip_;
464  char starting_ip_buf_[64];
465 };
466 #endif // OPENSSL_WINDOWS
467 
468 // g_in_trampoline is true if we are in an instrumented |abi_test_trampoline|
469 // call, in the region that triggers |SIGTRAP|.
470 static bool g_in_trampoline = false;
471 // g_unwind_function_done, if |g_in_trampoline| is true, is whether the function
472 // under test has returned. It is undefined otherwise.
473 static bool g_unwind_function_done;
474 // g_trampoline_state, if |g_in_trampoline| is true, is the state the function
475 // under test must preserve. It is undefined otherwise.
476 static CallerState g_trampoline_state;
477 // g_trampoline_sp, if |g_in_trampoline| is true, is the stack pointer of the
478 // trampoline frame. It is undefined otherwise.
479 static crypto_word_t g_trampoline_sp;
480 
481 // kMaxUnwindErrors is the maximum number of unwind errors reported per
482 // function. If a function's unwind tables are wrong, we are otherwise likely to
483 // repeat the same error at multiple addresses.
484 static constexpr size_t kMaxUnwindErrors = 10;
485 
486 // Errors are saved in a signal handler. We use a static buffer to avoid
487 // allocation.
488 static size_t g_num_unwind_errors = 0;
489 
490 struct UnwindError {
491 #if defined(OPENSSL_WINDOWS)
492  crypto_word_t ip;
493 #endif
494  char str[512];
495 };
496 
497 static UnwindError g_unwind_errors[kMaxUnwindErrors];
498 
499 template <typename... Args>
500 static void AddUnwindError(UnwindCursor *cursor, Args... args) {
501  if (g_num_unwind_errors >= kMaxUnwindErrors) {
502  return;
503  }
504 #if defined(OPENSSL_WINDOWS)
505  // Windows symbol functions should not be called when handling an
506  // exception. Stash the instruction pointer, to be symbolized later.
507  g_unwind_errors[g_num_unwind_errors].ip = cursor->starting_ip();
508  StrCatSignalSafe(g_unwind_errors[g_num_unwind_errors].str, args...);
509 #else
510  StrCatSignalSafe(g_unwind_errors[g_num_unwind_errors].str,
511  "unwinding at ", cursor->ToString(), ": ", args...);
512 #endif
513  g_num_unwind_errors++;
514 }
515 
516 static void CheckUnwind(UnwindCursor *cursor) {
517  const crypto_word_t kStartAddress =
518  reinterpret_cast<crypto_word_t>(&abi_test_unwind_start);
519  const crypto_word_t kReturnAddress =
520  reinterpret_cast<crypto_word_t>(&abi_test_unwind_return);
521  const crypto_word_t kStopAddress =
522  reinterpret_cast<crypto_word_t>(&abi_test_unwind_stop);
523 
524  crypto_word_t sp = cursor->GetSP().ValueOrDie("Error getting stack pointer");
525  crypto_word_t ip =
526  cursor->GetIP().ValueOrDie("Error getting instruction pointer");
527  if (!g_in_trampoline) {
528  if (ip != kStartAddress) {
529  FatalError("Unexpected SIGTRAP at ", cursor->ToString());
530  }
531 
532  // Save the current state and begin.
533  g_in_trampoline = true;
534  g_unwind_function_done = false;
535  g_trampoline_sp = sp;
536  g_trampoline_state = cursor->GetCallerState().ValueOrDie(
537  "Error getting initial caller state");
538  } else {
539  if (sp == g_trampoline_sp || g_unwind_function_done) {
540  // |g_unwind_function_done| should imply |sp| is |g_trampoline_sp|, but
541  // clearing the trap flag in x86 briefly displaces the stack pointer.
542  //
543  // Also note we check both |ip| and |sp| below, in case the function under
544  // test is also |abi_test_trampoline|.
545  if (ip == kReturnAddress && sp == g_trampoline_sp) {
546  g_unwind_function_done = true;
547  }
548  if (ip == kStopAddress && sp == g_trampoline_sp) {
549  // |SIGTRAP| is fatal again.
550  g_in_trampoline = false;
551  }
552  } else if (IsAncestorStackFrame(sp, g_trampoline_sp)) {
553  // This should never happen. We went past |g_trampoline_sp| without
554  // stopping at |kStopAddress|.
555  AddUnwindError(cursor, "stack frame is before caller");
556  g_in_trampoline = false;
557  } else if (g_num_unwind_errors < kMaxUnwindErrors) {
558  for (;;) {
559  UnwindStatusOr<bool> step_ret = cursor->Step();
560  if (!step_ret.ok()) {
561  AddUnwindError(cursor, "error unwinding: ", step_ret.Error());
562  break;
563  }
564  // |Step| returns whether there was a frame to unwind.
565  if (!step_ret.ValueOrDie()) {
566  AddUnwindError(cursor, "could not unwind to starting frame");
567  break;
568  }
569 
570  UnwindStatusOr<crypto_word_t> cur_sp = cursor->GetSP();
571  if (!cur_sp.ok()) {
572  AddUnwindError(cursor,
573  "error recovering stack pointer: ", cur_sp.Error());
574  break;
575  }
576  if (IsAncestorStackFrame(cur_sp.ValueOrDie(), g_trampoline_sp)) {
577  AddUnwindError(cursor, "unwound past starting frame");
578  break;
579  }
580  if (cur_sp.ValueOrDie() == g_trampoline_sp) {
581  // We found the parent frame. Check the return address.
582  UnwindStatusOr<crypto_word_t> cur_ip = cursor->GetIP();
583  if (!cur_ip.ok()) {
584  AddUnwindError(cursor,
585  "error recovering return address: ", cur_ip.Error());
586  } else if (cur_ip.ValueOrDie() != kReturnAddress) {
587  AddUnwindError(cursor, "wrong return address");
588  }
589 
590  // Check the remaining registers.
591  UnwindStatusOr<CallerState> state = cursor->GetCallerState();
592  if (!state.ok()) {
593  AddUnwindError(cursor,
594  "error recovering registers: ", state.Error());
595  } else {
596  ForEachMismatch(state.ValueOrDie(), g_trampoline_state,
597  [&](const char *reg) {
598  AddUnwindError(cursor, reg, " was not recovered");
599  });
600  }
601  break;
602  }
603  }
604  }
605  }
606 }
607 
608 static void ReadUnwindResult(Result *out) {
609  for (size_t i = 0; i < g_num_unwind_errors; i++) {
610 #if defined(OPENSSL_WINDOWS)
611  const crypto_word_t ip = g_unwind_errors[i].ip;
612  char buf[256];
613  DWORD64 displacement;
614  struct {
615  SYMBOL_INFO info;
616  char name_buf[128];
617  } symbol;
618  memset(&symbol, 0, sizeof(symbol));
619  symbol.info.SizeOfStruct = sizeof(symbol.info);
620  symbol.info.MaxNameLen = sizeof(symbol.name_buf);
621  if (SymFromAddr(GetCurrentProcess(), ip, &displacement, &symbol.info)) {
622  snprintf(buf, sizeof(buf), "unwinding at %s+%llu (0x%s): %s",
623  symbol.info.Name, displacement, WordToHex(ip).data(),
624  g_unwind_errors[i].str);
625  } else {
626  snprintf(buf, sizeof(buf), "unwinding at 0x%s: %s",
627  WordToHex(ip).data(), g_unwind_errors[i].str);
628  }
629  out->errors.emplace_back(buf);
630 #else
631  out->errors.emplace_back(g_unwind_errors[i].str);
632 #endif
633  }
634  if (g_num_unwind_errors == kMaxUnwindErrors) {
635  out->errors.emplace_back("(additional errors omitted)");
636  }
637  g_num_unwind_errors = 0;
638 }
639 
640 #if defined(OPENSSL_WINDOWS)
641 static DWORD g_main_thread;
642 
643 static long ExceptionHandler(EXCEPTION_POINTERS *info) {
644  if (info->ExceptionRecord->ExceptionCode != EXCEPTION_SINGLE_STEP ||
645  GetCurrentThreadId() != g_main_thread) {
646  return EXCEPTION_CONTINUE_SEARCH;
647  }
648 
649  UnwindCursor cursor(*info->ContextRecord);
650  CheckUnwind(&cursor);
651  if (g_in_trampoline) {
652  // Windows clears the trap flag, so we must restore it.
653  info->ContextRecord->EFlags |= 0x100;
654  }
655  return EXCEPTION_CONTINUE_EXECUTION;
656 }
657 
658 static void EnableUnwindTestsImpl() {
659  if (IsDebuggerPresent()) {
660  // Unwind tests drive logic via |EXCEPTION_SINGLE_STEP|, which conflicts with
661  // debuggers.
662  fprintf(stderr, "Debugger detected. Disabling unwind tests.\n");
663  return;
664  }
665 
666  g_main_thread = GetCurrentThreadId();
667 
668  SymSetOptions(SYMOPT_DEFERRED_LOADS);
669  if (!SymInitialize(GetCurrentProcess(), nullptr, TRUE)) {
670  fprintf(stderr, "Could not initialize symbols.\n");
671  }
672 
673  if (AddVectoredExceptionHandler(0, ExceptionHandler) == nullptr) {
674  fprintf(stderr, "Error installing exception handler.\n");
675  abort();
676  }
677 
678  g_unwind_tests_enabled = true;
679 }
680 #else // !OPENSSL_WINDOWS
681 // HandleEINTR runs |func| and returns the result, retrying the operation on
682 // |EINTR|.
683 template <typename Func>
684 static auto HandleEINTR(const Func &func) -> decltype(func()) {
685  decltype(func()) ret;
686  do {
687  ret = func();
688  } while (ret < 0 && errno == EINTR);
689  return ret;
690 }
691 
692 static bool ReadFileToString(std::string *out, const char *path) {
693  out->clear();
694 
695  int fd = HandleEINTR([&] { return open(path, O_RDONLY); });
696  if (fd < 0) {
697  return false;
698  }
699 
700  for (;;) {
701  char buf[1024];
702  ssize_t ret = HandleEINTR([&] { return read(fd, buf, sizeof(buf)); });
703  if (ret < 0) {
704  close(fd);
705  return false;
706  }
707  if (ret == 0) {
708  close(fd);
709  return true;
710  }
711  out->append(buf, static_cast<size_t>(ret));
712  }
713 }
714 
715 static bool IsBeingDebugged() {
717  if (!ReadFileToString(&status, "/proc/self/status")) {
718  perror("error reading /proc/self/status");
719  return false;
720  }
721  std::string key = "\nTracerPid:\t";
722  size_t idx = status.find(key);
723  if (idx == std::string::npos) {
724  return false;
725  }
726  idx += key.size();
727  return idx < status.size() && status[idx] != '0';
728 }
729 
730 static pthread_t g_main_thread;
731 
732 static void TrapHandler(int sig) {
733  // Note this is a signal handler, so only async-signal-safe functions may be
734  // used here. See signal-safety(7). libunwind promises local unwind is
735  // async-signal-safe.
736 
737  // |pthread_equal| is not listed as async-signal-safe, but this is clearly an
738  // oversight.
739  if (!pthread_equal(g_main_thread, pthread_self())) {
740  FatalError("SIGTRAP on background thread");
741  }
742 
743  unw_context_t ctx;
744  int ret = unw_getcontext(&ctx);
745  if (ret < 0) {
746  FatalError("Error getting unwind context: ", unw_strerror(ret));
747  }
748 
749  UnwindCursor cursor(&ctx);
750  CheckUnwind(&cursor);
751 }
752 
753 static void EnableUnwindTestsImpl() {
754  if (IsBeingDebugged()) {
755  // Unwind tests drive logic via |SIGTRAP|, which conflicts with debuggers.
756  fprintf(stderr, "Debugger detected. Disabling unwind tests.\n");
757  return;
758  }
759 
760  g_main_thread = pthread_self();
761 
762  struct sigaction trap_action;
763  OPENSSL_memset(&trap_action, 0, sizeof(trap_action));
764  sigemptyset(&trap_action.sa_mask);
765  trap_action.sa_handler = TrapHandler;
766  if (sigaction(SIGTRAP, &trap_action, NULL) != 0) {
767  perror("sigaction");
768  abort();
769  }
770 
771  g_unwind_tests_enabled = true;
772 }
773 #endif // OPENSSL_WINDOWS
774 
775 #else // !SUPPORTS_UNWIND_TEST
776 
777 #if defined(SUPPORTS_ABI_TEST)
778 static void ReadUnwindResult(Result *) {}
779 #endif
780 static void EnableUnwindTestsImpl() {}
781 
782 #endif // SUPPORTS_UNWIND_TEST
783 
784 } // namespace internal
785 
787 
789 
790 } // namespace abi_test
xds_interop_client.str
str
Definition: xds_interop_client.py:487
gen_build_yaml.out
dictionary out
Definition: src/benchmark/gen_build_yaml.py:24
RAND_bytes
#define RAND_bytes
Definition: boringssl_prefix_symbols.h:2060
ctx
Definition: benchmark-async.c:30
memset
return memset(p, 0, total)
write
#define write
Definition: test-fs.c:47
abi_test_unwind_return
#define abi_test_unwind_return
Definition: boringssl_prefix_symbols.h:2790
check_version.warning
string warning
Definition: check_version.py:46
string.h
buf
voidpf void * buf
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
array
PHP_PROTO_OBJECT_FREE_END PHP_PROTO_OBJECT_DTOR_END intern array
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/array.c:111
testing::internal::string
::std::string string
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:881
error_ref_leak.err
err
Definition: error_ref_leak.py:35
abi_test_trampoline
#define abi_test_trampoline
Definition: boringssl_prefix_symbols.h:2789
abi_test_get_and_clear_direction_flag
#define abi_test_get_and_clear_direction_flag
Definition: boringssl_prefix_symbols.h:2787
status
absl::Status status
Definition: rls.cc:251
ctx
static struct test_ctx ctx
Definition: test-ipc-send-recv.c:65
check_documentation.path
path
Definition: check_documentation.py:57
ctx_
ClientContext ctx_
Definition: client_interceptors_end2end_test.cc:289
abi_test::internal::EnableUnwindTestsImpl
static void EnableUnwindTestsImpl()
Definition: abi_test.cc:780
uint8_t
unsigned char uint8_t
Definition: stdint-msvc2008.h:78
OPENSSL_memset
static void * OPENSSL_memset(void *dst, int c, size_t n)
Definition: third_party/boringssl-with-bazel/src/crypto/internal.h:835
T
#define T(upbtypeconst, upbtype, ctype, default_value)
python_utils.port_server.stderr
stderr
Definition: port_server.py:51
abi_test_unwind_start
#define abi_test_unwind_start
Definition: boringssl_prefix_symbols.h:2791
abi_test::internal::g_unwind_tests_enabled
static bool g_unwind_tests_enabled
Definition: abi_test.cc:60
memcpy
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
ssize_t
intptr_t ssize_t
Definition: win.h:27
asyncio_get_stats.args
args
Definition: asyncio_get_stats.py:40
abi_test
Definition: abi_test.cc:56
hpack_encoder_fixtures::Args
Args({0, 16384})
ToString
std::string ToString(const grpc::string_ref &r)
Definition: string_ref_helper.cc:24
re2::Result
TestInstance::Result Result
Definition: bloaty/third_party/re2/re2/testing/tester.cc:96
absl::random_internal_nanobenchmark::Func
FuncOutput(*)(const void *, FuncInput) Func
Definition: abseil-cpp/absl/random/internal/nanobenchmark.h:68
setup.v
v
Definition: third_party/bloaty/third_party/capstone/bindings/python/setup.py:42
abi_test::internal::FixVAArgsString
std::string FixVAArgsString(const char *str)
Definition: abi_test.cc:62
std::swap
void swap(Json::Value &a, Json::Value &b)
Specialize std::swap() for Json::Value.
Definition: third_party/bloaty/third_party/protobuf/conformance/third_party/jsoncpp/json.h:1226
close
#define close
Definition: test-fs.c:48
OPENSSL_MSVC_PRAGMA
OPENSSL_MSVC_PRAGMA(warning(disable:4702))
Definition: e_aes.c:69
status_
absl::Status status_
Definition: outlier_detection.cc:404
data
char data[kBufferLength]
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1006
b
uint64_t b
Definition: abseil-cpp/absl/container/internal/layout_test.cc:53
setup.idx
idx
Definition: third_party/bloaty/third_party/capstone/bindings/python/setup.py:197
msg
std::string msg
Definition: client_interceptors_end2end_test.cc:372
OPENSSL_strlcat
#define OPENSSL_strlcat
Definition: boringssl_prefix_symbols.h:1893
push
int push(void *desc, unsigned char *buf, unsigned len)
Definition: bloaty/third_party/zlib/test/infcover.c:463
value_
int value_
Definition: orphanable_test.cc:38
value
const char * value
Definition: hpack_parser_table.cc:165
read
int read(izstream &zs, T *x, Items items)
Definition: bloaty/third_party/zlib/contrib/iostream2/zstream.h:115
rand.h
func
const EVP_CIPHER *(* func)(void)
Definition: cipher_extra.c:73
key
const char * key
Definition: hpack_parser_table.cc:164
ret
UniquePtr< SSL_SESSION > ret
Definition: ssl_x509.cc:1029
INVALID_HANDLE_VALUE
#define INVALID_HANDLE_VALUE
Definition: bloaty/third_party/zlib/contrib/minizip/iowin32.c:21
abi_test::UnwindTestsEnabled
bool UnwindTestsEnabled()
Definition: abi_test.cc:788
ok
bool ok
Definition: async_end2end_test.cc:197
state
Definition: bloaty/third_party/zlib/contrib/blast/blast.c:41
absl::Status::ok
ABSL_MUST_USE_RESULT bool ok() const
Definition: third_party/abseil-cpp/absl/status/status.h:802
abi_test.h
open
#define open
Definition: test-fs.c:46
DECIMAL_SIZE
#define DECIMAL_SIZE(type)
Definition: mem.h:124
internal
Definition: benchmark/test/output_test_helper.cc:20
span.h
mem.h
len
int len
Definition: abseil-cpp/absl/base/internal/low_level_alloc_test.cc:46
abi_test_unwind_stop
#define abi_test_unwind_stop
Definition: boringssl_prefix_symbols.h:2792
abi_test::EnableUnwindTests
void EnableUnwindTests()
Definition: abi_test.cc:786
errno.h
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
state
static struct rpc_state state
Definition: bad_server_response_test.cc:87


grpc
Author(s):
autogenerated on Fri May 16 2025 02:57:39