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 
21 namespace lldb_private {
22 namespace instrumentation {
23 
24 template <typename T, std::enable_if_t<std::is_fundamental<T>::value, int> = 0>
stringify_append(llvm::raw_string_ostream & ss,const T & t)25 inline void stringify_append(llvm::raw_string_ostream &ss, const T &t) {
26   ss << t;
27 }
28 
29 template <typename T, std::enable_if_t<!std::is_fundamental<T>::value, int> = 0>
stringify_append(llvm::raw_string_ostream & ss,const T & t)30 inline void stringify_append(llvm::raw_string_ostream &ss, const T &t) {
31   ss << &t;
32 }
33 
34 template <typename T>
stringify_append(llvm::raw_string_ostream & ss,T * t)35 inline void stringify_append(llvm::raw_string_ostream &ss, T *t) {
36   ss << reinterpret_cast<void *>(t);
37 }
38 
39 template <typename T>
stringify_append(llvm::raw_string_ostream & ss,const T * t)40 inline void stringify_append(llvm::raw_string_ostream &ss, const T *t) {
41   ss << reinterpret_cast<const void *>(t);
42 }
43 
44 template <>
45 inline void stringify_append<char>(llvm::raw_string_ostream &ss,
46                                    const char *t) {
47   ss << '\"' << t << '\"';
48 }
49 
50 template <>
51 inline void stringify_append<std::nullptr_t>(llvm::raw_string_ostream &ss,
52                                              const std::nullptr_t &t) {
53   ss << "\"nullptr\"";
54 }
55 
56 template <typename Head>
stringify_helper(llvm::raw_string_ostream & ss,const Head & head)57 inline void stringify_helper(llvm::raw_string_ostream &ss, const Head &head) {
58   stringify_append(ss, head);
59 }
60 
61 template <typename Head, typename... Tail>
stringify_helper(llvm::raw_string_ostream & ss,const Head & head,const Tail &...tail)62 inline void stringify_helper(llvm::raw_string_ostream &ss, const Head &head,
63                              const Tail &...tail) {
64   stringify_append(ss, head);
65   ss << ", ";
66   stringify_helper(ss, tail...);
67 }
68 
stringify_args(const Ts &...ts)69 template <typename... Ts> inline std::string stringify_args(const Ts &...ts) {
70   std::string buffer;
71   llvm::raw_string_ostream ss(buffer);
72   stringify_helper(ss, ts...);
73   return ss.str();
74 }
75 
76 /// RAII object for instrumenting LLDB API functions.
77 class Instrumenter {
78 public:
79   Instrumenter(llvm::StringRef pretty_func, std::string &&pretty_args = {});
80   ~Instrumenter();
81 
82 private:
83   void UpdateBoundary();
84 
85   llvm::StringRef m_pretty_func;
86 
87   /// Whether this function call was the one crossing the API boundary.
88   bool m_local_boundary = false;
89 };
90 } // namespace instrumentation
91 } // namespace lldb_private
92 
93 #define LLDB_INSTRUMENT()                                                      \
94   lldb_private::instrumentation::Instrumenter _instr(LLVM_PRETTY_FUNCTION);
95 
96 #define LLDB_INSTRUMENT_VA(...)                                                \
97   lldb_private::instrumentation::Instrumenter _instr(                          \
98       LLVM_PRETTY_FUNCTION,                                                    \
99       lldb_private::instrumentation::stringify_args(__VA_ARGS__));
100 
101 #endif // LLDB_UTILITY_INSTRUMENTATION_H
102