xref: /aosp_15_r20/external/fbjni/cxx/lyra/lyra.h (revision 65c59e023c5336bbd4a23be7af78407e3d80e7e7)
1 /*
2  * Copyright (c) Facebook, Inc. and its affiliates.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <iomanip>
20 #include <string>
21 #include <vector>
22 
23 namespace facebook {
24 namespace lyra {
25 
26 constexpr size_t kDefaultLimit = 64;
27 
28 using InstructionPointer = const void*;
29 
30 class StackTraceElement {
31  public:
StackTraceElement(InstructionPointer absoluteProgramCounter,InstructionPointer libraryBase,InstructionPointer functionAddress,std::string libraryName,std::string functionName)32   StackTraceElement(
33       InstructionPointer absoluteProgramCounter,
34       InstructionPointer libraryBase,
35       InstructionPointer functionAddress,
36       std::string libraryName,
37       std::string functionName)
38       : absoluteProgramCounter_{absoluteProgramCounter},
39         libraryBase_{libraryBase},
40         functionAddress_{functionAddress},
41         libraryName_{std::move(libraryName)},
42         functionName_{std::move(functionName)},
43         hasBuildId_{false},
44         buildId_{} {}
45 
libraryBase()46   InstructionPointer libraryBase() const noexcept {
47     return libraryBase_;
48   }
49 
functionAddress()50   InstructionPointer functionAddress() const noexcept {
51     return functionAddress_;
52   }
53 
absoluteProgramCounter()54   InstructionPointer absoluteProgramCounter() const noexcept {
55     return absoluteProgramCounter_;
56   }
57 
libraryName()58   const std::string& libraryName() const noexcept {
59     return libraryName_;
60   }
61 
functionName()62   const std::string& functionName() const noexcept {
63     return functionName_;
64   }
65 
66   /**
67    * The offset of the program counter to the base of the library (i.e. the
68    * address that addr2line takes as input>
69    */
libraryOffset()70   std::ptrdiff_t libraryOffset() const noexcept {
71     auto absoluteLibrary = static_cast<const char*>(libraryBase_);
72     auto absoluteabsoluteProgramCounter =
73         static_cast<const char*>(absoluteProgramCounter_);
74     return absoluteabsoluteProgramCounter - absoluteLibrary;
75   }
76 
77   /**
78    * The offset within the current function
79    */
functionOffset()80   int functionOffset() const noexcept {
81     auto absoluteSymbol = static_cast<const char*>(functionAddress_);
82     auto absoluteabsoluteProgramCounter =
83         static_cast<const char*>(absoluteProgramCounter_);
84     return absoluteabsoluteProgramCounter - absoluteSymbol;
85   }
86 
87   std::string buildId() const;
88 
89  private:
90   const InstructionPointer absoluteProgramCounter_;
91   const InstructionPointer libraryBase_;
92   const InstructionPointer functionAddress_;
93   const std::string libraryName_;
94   const std::string functionName_;
95 
96   mutable bool hasBuildId_;
97   mutable std::string buildId_;
98 };
99 
100 /**
101  * If a library identifier function is set, it is passed a libraryName
102  * for the frame, and returns a library build id string, which will be
103  * included in the logged stack trace.  The most common use for this
104  * will be correlating stack traces with breakpad identifiers.
105  */
106 typedef std::string (*LibraryIdentifierFunctionType)(const std::string&);
107 
108 void setLibraryIdentifierFunction(LibraryIdentifierFunctionType func);
109 
110 /**
111  * Populate the vector with the current stack trace
112  *
113  * Note that this trace needs to be symbolicated to get the library offset even
114  * if it is to be symbolicated off-line.
115  *
116  * Beware of a bug on some platforms, which makes the trace loop until the
117  * buffer is full when it reaches a noexpr function. It seems to be fixed in
118  * newer versions of gcc. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56846
119  *
120  * @param stackTrace The vector that will receive the stack trace. Before
121  * filling the vector it will be cleared. The vector will never grow so the
122  * number of frames captured is limited by the capacity of it.
123  *
124  * @param skip The number of frames to skip before capturing the trace
125  */
126 void getStackTrace(
127     std::vector<InstructionPointer>& stackTrace,
128     size_t skip = 0);
129 
130 /**
131  * Creates a vector and populates it with the current stack trace
132  *
133  * Note that this trace needs to be symbolicated to get the library offset even
134  * if it is to be symbolicated off-line.
135  *
136  * Beware of a bug on some platforms, which makes the trace loop until the
137  * buffer is full when it reaches a noexpr function. It seems to be fixed in
138  * newer versions of gcc. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56846
139  *
140  * @param skip The number of frames to skip before capturing the trace
141  *
142  * @limit The maximum number of frames captured
143  */
144 inline std::vector<InstructionPointer> getStackTrace(
145     size_t skip = 0,
146     size_t limit = kDefaultLimit) {
147   auto stackTrace = std::vector<InstructionPointer>{};
148   stackTrace.reserve(limit);
149   getStackTrace(stackTrace, skip + 1);
150   return stackTrace;
151 }
152 
153 /**
154  * Symbolicates a stack trace into a given vector
155  *
156  * @param symbols The vector to receive the output. The vector is cleared and
157  * enough room to keep the frames are reserved.
158  *
159  * @param stackTrace The input stack trace
160  */
161 void getStackTraceSymbols(
162     std::vector<StackTraceElement>& symbols,
163     const std::vector<InstructionPointer>& trace);
164 
165 /**
166  * Symbolicates a stack trace into a new vector
167  *
168  * @param stackTrace The input stack trace
169  */
getStackTraceSymbols(const std::vector<InstructionPointer> & trace)170 inline std::vector<StackTraceElement> getStackTraceSymbols(
171     const std::vector<InstructionPointer>& trace) {
172   auto symbols = std::vector<StackTraceElement>{};
173   getStackTraceSymbols(symbols, trace);
174   return symbols;
175 }
176 
177 /**
178  * Captures and symbolicates a stack trace
179  *
180  * Beware of a bug on some platforms, which makes the trace loop until the
181  * buffer is full when it reaches a noexpr function. It seems to be fixed in
182  * newer versions of gcc. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56846
183  *
184  * @param skip The number of frames before capturing the trace
185  *
186  * @param limit The maximum number of frames captured
187  */
188 inline std::vector<StackTraceElement> getStackTraceSymbols(
189     size_t skip = 0,
190     size_t limit = kDefaultLimit) {
191   return getStackTraceSymbols(getStackTrace(skip + 1, limit));
192 }
193 
194 /**
195  * Formatting a stack trace element
196  */
197 std::ostream& operator<<(std::ostream& out, const StackTraceElement& elm);
198 
199 /**
200  * Formatting a stack trace
201  */
202 std::ostream& operator<<(
203     std::ostream& out,
204     const std::vector<StackTraceElement>& trace);
205 
206 /**
207  * Log stack trace
208  *
209  * Makes it possible to log a trace without using a temporary stream when the
210  * underlying log API is not stream based.
211  */
212 void logStackTrace(const std::vector<StackTraceElement>& trace);
213 
214 } // namespace lyra
215 } // namespace facebook
216