• 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 <unordered_map>
24 
25 namespace rr {
26 
27 namespace {
to_lower(std::string str)28 std::string to_lower(std::string str)
29 {
30 	std::transform(str.begin(), str.end(), str.begin(),
31 	               [](unsigned char c) { return std::tolower(c); });
32 	return str;
33 }
34 
endswith_lower(const std::string & str,const std::string & suffix)35 bool endswith_lower(const std::string &str, const std::string &suffix)
36 {
37 	size_t strLen = str.size();
38 	size_t suffixLen = suffix.size();
39 
40 	if(strLen < suffixLen)
41 	{
42 		return false;
43 	}
44 
45 	return to_lower(str).substr(strLen - suffixLen) == to_lower(suffix);
46 }
47 }  // namespace
48 
getCallerBacktrace(size_t limit)49 Backtrace getCallerBacktrace(size_t limit /* = 0 */)
50 {
51 	auto shouldSkipFile = [](const std::string &fileSR) {
52 		return fileSR.empty() ||
53 		       endswith_lower(fileSR, "ReactorDebugInfo.cpp") ||
54 		       endswith_lower(fileSR, "Reactor.cpp") ||
55 		       endswith_lower(fileSR, "Reactor.hpp") ||
56 		       endswith_lower(fileSR, "Traits.hpp") ||
57 		       endswith_lower(fileSR, "stacktrace.hpp");
58 	};
59 
60 	std::vector<Location> locations;
61 
62 	namespace bs = boost::stacktrace;
63 
64 	// Cache to avoid expensive stacktrace lookups, especially since our use-case results in looking up the
65 	// same call stack addresses many times.
66 	static std::unordered_map<bs::frame::native_frame_ptr_t, Location> cache;
67 
68 	for(bs::frame frame : bs::stacktrace())
69 	{
70 		Location location;
71 
72 		auto iter = cache.find(frame.address());
73 		if(iter == cache.end())
74 		{
75 			location.function.file = frame.source_file();
76 			location.function.name = frame.name();
77 			location.line = frame.source_line();
78 			cache[frame.address()] = location;
79 		}
80 		else
81 		{
82 			location = iter->second;
83 		}
84 
85 		if(shouldSkipFile(location.function.file))
86 		{
87 			continue;
88 		}
89 
90 		locations.push_back(std::move(location));
91 
92 		if(limit > 0 && locations.size() >= limit)
93 		{
94 			break;
95 		}
96 	}
97 
98 	std::reverse(locations.begin(), locations.end());
99 
100 	return locations;
101 }
102 
emitPrintLocation(const Backtrace & backtrace)103 void emitPrintLocation(const Backtrace &backtrace)
104 {
105 	static Location lastLocation;
106 	if(backtrace.size() == 0)
107 	{
108 		return;
109 	}
110 	Location currLocation = backtrace[backtrace.size() - 1];
111 	if(currLocation != lastLocation)
112 	{
113 		rr::Print("rr> {0} [{1}:{2}]\n", currLocation.function.name.c_str(), currLocation.function.file.c_str(), currLocation.line);
114 		lastLocation = std::move(currLocation);
115 	}
116 }
117 
118 }  // namespace rr
119 
120 #endif  // ENABLE_RR_DEBUG_INFO
121