1//===-- Instrumentation.h ---------------------------------------*- C++ -*-===//
2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3// See https://llvm.org/LICENSE.txt for license information.
4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5//
6//===----------------------------------------------------------------------===//
7
8#ifndef LLDB_UTILITY_INSTRUMENTATION_H
9#define LLDB_UTILITY_INSTRUMENTATION_H
10
11#include "lldb/Utility/FileSpec.h"
12#include "lldb/Utility/Log.h"
13#include "llvm/ADT/DenseMap.h"
14#include "llvm/ADT/StringRef.h"
15#include "llvm/Support/ErrorHandling.h"
16
17#include <map>
18#include <thread>
19#include <type_traits>
20
21namespace lldb_private {
22namespace instrumentation {
23
24template <typename T,
25          typename std::enable_if<std::is_fundamental<T>::value, int>::type = 0>
26inline void stringify_append(llvm::raw_string_ostream &ss, const T &t) {
27  ss << t;
28}
29
30template <typename T, typename std::enable_if<!std::is_fundamental<T>::value,
31                                              int>::type = 0>
32inline void stringify_append(llvm::raw_string_ostream &ss, const T &t) {
33  ss << &t;
34}
35
36template <typename T>
37inline void stringify_append(llvm::raw_string_ostream &ss, T *t) {
38  ss << reinterpret_cast<void *>(t);
39}
40
41template <typename T>
42inline void stringify_append(llvm::raw_string_ostream &ss, const T *t) {
43  ss << reinterpret_cast<const void *>(t);
44}
45
46template <>
47inline void stringify_append<char>(llvm::raw_string_ostream &ss,
48                                   const char *t) {
49  ss << '\"' << t << '\"';
50}
51
52template <>
53inline void stringify_append<std::nullptr_t>(llvm::raw_string_ostream &ss,
54                                             const std::nullptr_t &t) {
55  ss << "\"nullptr\"";
56}
57
58template <typename Head>
59inline void stringify_helper(llvm::raw_string_ostream &ss, const Head &head) {
60  stringify_append(ss, head);
61}
62
63template <typename Head, typename... Tail>
64inline void stringify_helper(llvm::raw_string_ostream &ss, const Head &head,
65                             const Tail &...tail) {
66  stringify_append(ss, head);
67  ss << ", ";
68  stringify_helper(ss, tail...);
69}
70
71template <typename... Ts> inline std::string stringify_args(const Ts &...ts) {
72  std::string buffer;
73  llvm::raw_string_ostream ss(buffer);
74  stringify_helper(ss, ts...);
75  return ss.str();
76}
77
78/// RAII object for instrumenting LLDB API functions.
79class Instrumenter {
80public:
81  Instrumenter(llvm::StringRef pretty_func, std::string &&pretty_args = {});
82  ~Instrumenter();
83
84private:
85  void UpdateBoundary();
86
87  llvm::StringRef m_pretty_func;
88
89  /// Whether this function call was the one crossing the API boundary.
90  bool m_local_boundary = false;
91};
92} // namespace instrumentation
93} // namespace lldb_private
94
95#define LLDB_INSTRUMENT()                                                      \
96  lldb_private::instrumentation::Instrumenter _instr(LLVM_PRETTY_FUNCTION);
97
98#define LLDB_INSTRUMENT_VA(...)                                                \
99  lldb_private::instrumentation::Instrumenter _instr(                          \
100      LLVM_PRETTY_FUNCTION,                                                    \
101      lldb_private::instrumentation::stringify_args(__VA_ARGS__));
102
103#endif // LLDB_UTILITY_INSTRUMENTATION_H
104