1
2
3
4
5
6 #include <cmajor/rt/Unwind.hpp>
7 #include <memory>
8 #include <string>
9 #include <unordered_map>
10 #include <vector>
11
12 #ifdef _WIN32
13
14 #else
15 void* unwindList = nullptr;
16 #endif
17
18 struct UnwindInfo
19 {
20 UnwindInfo* next;
21 void* function;
22 int32_t line;
23 };
24
25 void* RtPushUnwindInfo(void* unwindInfo)
26 {
27 void* prevUnwindInfo = unwindList;
28 unwindList = unwindInfo;
29 return prevUnwindInfo;
30 }
31
32 void RtPopUnwindInfo(void* prevUnwindInfo)
33 {
34 unwindList = prevUnwindInfo;
35 }
36
37 struct FunctionUnwindInfo
38 {
39 FunctionUnwindInfo(const char* functionName_, const char* sourceFilePath_) : functionName(functionName_), sourceFilePath(sourceFilePath_) {}
40 std::string functionName;
41 std::string sourceFilePath;
42 };
43
44 class GlobalUnwindInfo
45 {
46 public:
47 static void Init();
48 static void Done();
49 static bool Initialized() { return instance != nullptr; }
50 static GlobalUnwindInfo& Instance() { return *instance; }
51 void AddUnwindInfo(void* functionAddress, const char* functionName, const char* sourceFilePath);
52 const char* GetCallStack(UnwindInfo* unwindInfoList);
53 void DisposeCallStack(UnwindInfo* unwindInfoList);
54 private:
55 static std::unique_ptr<GlobalUnwindInfo> instance;
56 GlobalUnwindInfo();
57 std::unordered_map<void*, FunctionUnwindInfo*> unwindInfoMap;
58 std::vector<std::std::unique_ptr<FunctionUnwindInfo>>unwindInfoVec;
59 std::unordered_map<void*, std::string*> callStackMap;
60 };
61
62 void GlobalUnwindInfo::Init()
63 {
64 instance.reset(new GlobalUnwindInfo());
65 }
66
67 void GlobalUnwindInfo::Done()
68 {
69 instance.reset();
70 }
71
72 std::unique_ptr<GlobalUnwindInfo> GlobalUnwindInfo::instance;
73
74 GlobalUnwindInfo::GlobalUnwindInfo()
75 {
76 }
77
78 void GlobalUnwindInfo::AddUnwindInfo(void* functionAddress, const char* functionName, const char* sourceFilePath)
79 {
80 auto it = unwindInfoMap.find(functionAddress);
81 if (it == unwindInfoMap.cend())
82 {
83 FunctionUnwindInfo* unwindInfo = new FunctionUnwindInfo(functionName, sourceFilePath);
84 unwindInfoVec.push_back(std::unique_ptr<FunctionUnwindInfo>(unwindInfo));
85 unwindInfoMap[functionAddress] = unwindInfo;
86 }
87 }
88
89 const char* GlobalUnwindInfo::GetCallStack(UnwindInfo* unwindInfoList)
90 {
91 if (!unwindInfoList) return "";
92 auto it = callStackMap.find(unwindInfoList);
93 if (it != callStackMap.cend())
94 {
95 return it->second->c_str();
96 }
97 std::unique_ptr<std::string> callStack(new std::string());
98 UnwindInfo* unwindInfo = unwindInfoList;
99 while (unwindInfo)
100 {
101 void* function = unwindInfo->function;
102 auto it = unwindInfoMap.find(function);
103 if (it != unwindInfoMap.cend())
104 {
105 FunctionUnwindInfo* functionUnwindInfo = it->second;
106 callStack->append(functionUnwindInfo->functionName).append(1, ' ').append(functionUnwindInfo->sourceFilePath);
107 if (unwindInfo->line != 0 && unwindInfo->line != -1)
108 {
109 callStack->append(1, ':').append(std::to_string(unwindInfo->line));
110 }
111 callStack->append("\n");
112 }
113 unwindInfo = unwindInfo->next;
114 }
115 const char* callStackStr = callStack->c_str();
116 callStackMap[unwindInfoList] = callStack.release();
117 return callStackStr;
118 }
119
120 void GlobalUnwindInfo::DisposeCallStack(UnwindInfo* unwindInfoList)
121 {
122 auto it = callStackMap.find(unwindInfoList);
123 if (it != callStackMap.cend())
124 {
125 delete it->second;
126 callStackMap.erase(unwindInfoList);
127 }
128 }
129
130 void RtAddCompileUnitFunction(void* functionAddress, const char* functionName, const char* sourceFilePath)
131 {
132 if (GlobalUnwindInfo::Initialized())
133 {
134 GlobalUnwindInfo::Instance().AddUnwindInfo(functionAddress, functionName, sourceFilePath);
135 }
136 }
137
138 const char* RtGetCallStack()
139 {
140 if (GlobalUnwindInfo::Initialized())
141 {
142 return GlobalUnwindInfo::Instance().GetCallStack(static_cast<UnwindInfo*>(unwindList));
143 }
144 return "";
145 }
146
147 void RtDisposeCallStack()
148 {
149 if (GlobalUnwindInfo::Initialized())
150 {
151 GlobalUnwindInfo::Instance().DisposeCallStack(static_cast<UnwindInfo*>(unwindList));
152 }
153 }
154
155 void InitUnwind()
156 {
157 GlobalUnwindInfo::Init();
158 }
159
160 void DoneUnwind()
161 {
162 GlobalUnwindInfo::Done();
163 }