• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //  http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "ReactorDebugInfo.hpp"
16 #include "Print.hpp"
17 
18 #ifdef ENABLE_RR_DEBUG_INFO
19 
20 #	include "boost/stacktrace.hpp"
21 
22 #	include <algorithm>
23 #	include <cctype>
24 #	include <unordered_map>
25 
26 namespace rr {
27 
28 namespace {
to_lower(std::string str)29 std::string to_lower(std::string str)
30 {
31 	std::transform(str.begin(), str.end(), str.begin(),
32 	               [](unsigned char c) { return std::tolower(c); });
33 	return str;
34 }
35 
endswith_lower(const std::string & str,const std::string & suffix)36 bool endswith_lower(const std::string &str, const std::string &suffix)
37 {
38 	size_t strLen = str.size();
39 	size_t suffixLen = suffix.size();
40 
41 	if(strLen < suffixLen)
42 	{
43 		return false;
44 	}
45 
46 	return to_lower(str).substr(strLen - suffixLen) == to_lower(suffix);
47 }
48 }  // namespace
49 
getCallerBacktrace(size_t limit)50 Backtrace getCallerBacktrace(size_t limit /* = 0 */)
51 {
52 	namespace bs = boost::stacktrace;
53 
54 	auto shouldSkipFile = [](const std::string &fileSR) {
55 		return fileSR.empty() ||
56 		       endswith_lower(fileSR, "ReactorDebugInfo.cpp") ||
57 		       endswith_lower(fileSR, "Reactor.cpp") ||
58 		       endswith_lower(fileSR, "Reactor.hpp") ||
59 		       endswith_lower(fileSR, "Traits.hpp") ||
60 		       endswith_lower(fileSR, "stacktrace.hpp");
61 	};
62 
63 	auto offsetStackFrames = [](const bs::stacktrace &st) {
64 		// Return a stack trace with every stack frame address offset by -1. We do this so that we get
65 		// back the location of the function call, and not the location following it. We need this since
66 		// all debug info emits are the result of a function call. Note that technically we shouldn't
67 		// perform this offsetting on the top-most stack frame, but it doesn't matter as we discard it
68 		// anyway (see shouldSkipFile).
69 
70 		std::vector<bs::frame> result;
71 		result.reserve(st.size());
72 
73 		for(bs::frame frame : st)
74 		{
75 			result.emplace_back(reinterpret_cast<void *>(reinterpret_cast<size_t>(frame.address()) - 1));
76 		}
77 
78 		return result;
79 	};
80 
81 	std::vector<Location> locations;
82 
83 	// Cache to avoid expensive stacktrace lookups, especially since our use-case results in looking up the
84 	// same call stack addresses many times.
85 	static std::unordered_map<bs::frame::native_frame_ptr_t, Location> cache;
86 
87 	for(bs::frame frame : offsetStackFrames(bs::stacktrace()))
88 	{
89 		Location location;
90 
91 		auto iter = cache.find(frame.address());
92 		if(iter == cache.end())
93 		{
94 			location.function.file = frame.source_file();
95 			location.function.name = frame.name();
96 			location.line = frame.source_line();
97 			cache[frame.address()] = location;
98 		}
99 		else
100 		{
101 			location = iter->second;
102 		}
103 
104 		if(shouldSkipFile(location.function.file))
105 		{
106 			continue;
107 		}
108 
109 		locations.push_back(std::move(location));
110 
111 		if(limit > 0 && locations.size() >= limit)
112 		{
113 			break;
114 		}
115 	}
116 
117 	std::reverse(locations.begin(), locations.end());
118 
119 	return locations;
120 }
121 
emitPrintLocation(const Backtrace & backtrace)122 void emitPrintLocation(const Backtrace &backtrace)
123 {
124 #	ifdef ENABLE_RR_EMIT_PRINT_LOCATION
125 	static Location lastLocation;
126 	if(backtrace.size() == 0)
127 	{
128 		return;
129 	}
130 	Location currLocation = backtrace[backtrace.size() - 1];
131 	if(currLocation != lastLocation)
132 	{
133 		rr::Print("rr> {0} [{1}:{2}]\n", currLocation.function.name.c_str(), currLocation.function.file.c_str(), currLocation.line);
134 		lastLocation = std::move(currLocation);
135 	}
136 #	endif
137 }
138 
139 }  // namespace rr
140 
141 #endif  // ENABLE_RR_DEBUG_INFO
142