1 // =================================
  2 // Copyright (c) 2021 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 #include <cmajor/rt/CallStack.hpp>
  7 #include <cmajor/rt/Error.hpp>
  8 #include <cmajor/rt/Io.hpp>
  9 #include <soulng/util/Error.hpp>
 10 #include <vector>
 11 #include <sstream>
 12 #include <iostream>
 13 
 14 namespace cmajor { namespace rt {
 15 
 16 struct SourceLocation 
 17 {
 18     SourceLocation(const char* functionName_const char* sourceFilePath_);
 19     const char* functionName;
 20     const char* sourceFilePath;
 21     int32_t lineNumber;
 22 };
 23 
 24 SourceLocation::SourceLocation(const char* functionName_const char* sourceFilePath_) : functionName(functionName_)sourceFilePath(sourceFilePath_)lineNumber(0)
 25 {
 26 }
 27 
 28 class CallStack 
 29 {
 30 public:
 31     CallStack();
 32     std::std::vector<SourceLocation>&Locations(){returnlocations;}
 33 private:
 34     std::vector<SourceLocation> locations;
 35 };
 36 
 37 CallStack::CallStack()
 38 {
 39 }
 40 
 41 #ifdef _WIN32
 42 
 43 
 44 
 45 #else
 46 
 47          CallStack* callStack = nullptr;
 48 
 49 #endif
 50 
 51 #ifdef _WIN32
 52 
 53 
 54 
 55 #else
 56 
 57          std::string* stackTrace = nullptr;
 58 
 59 #endif
 60 
 61 } }  // namespace cmajor::rt
 62 
 63 int indent = 0;
 64 
 65 extern "C" void RtEnterFunction(const char* functionName, const char* sourceFilePath)
 66 {
 67     cmajor::rt::CallStack* callStack = cmajor::rt::callStack;
 68     if (!callStack)
 69     {
 70         callStack = new cmajor::rt::CallStack();
 71         cmajor::rt::callStack = callStack;
 72     }
 73     callStack->Locations().push_back(cmajor::rt::SourceLocation(functionName, sourceFilePath));
 74 }
 75 
 76 extern "C" void RtSetLineNumber(int32_t lineNumber)
 77 {
 78     try
 79     {
 80         cmajor::rt::CallStack* callStack = cmajor::rt::callStack;
 81         Assert(callStack && !callStack->Locations().empty(), "call stack is empty");
 82         callStack->Locations().back().lineNumber = lineNumber;
 83     }
 84     catch (const std::exception& ex)
 85     {
 86         std::stringstream s;
 87         s << "internal error: " << ex.what() << "\n";
 88         std::string str = s.str();
 89         int32_t errorStringHandle = -1;
 90         void* stdErr = RtOpenStdFile(2, errorStringHandle);
 91         RtWrite(stdErr, reinterpret_cast<const uint8_t*>(str.c_str()), str.length(), errorStringHandle);
 92         exit(exitCodeInternalError);
 93     }
 94 }
 95 
 96 extern "C" void RtExitFunction()
 97 {
 98     try
 99     {
100         cmajor::rt::CallStack* callStack = cmajor::rt::callStack;
101         Assert(callStack && !callStack->Locations().empty(), "call stack is empty");
102         callStack->Locations().pop_back();
103     }
104     catch (const std::exception& ex)
105     {
106         std::stringstream s;
107         s << "internal error: " << ex.what() << "\n";
108         std::string str = s.str();
109         int32_t errorStringHandle = -1;
110         void* stdError = RtOpenStdFile(2, errorStringHandle);
111         RtWrite(stdError, reinterpret_cast<const uint8_t*>(str.c_str()), str.length(), errorStringHandle);
112         RtFlush(stdError, errorStringHandle);
113         exit(exitCodeInternalError);
114     }
115 }
116 
117 extern "C" void RtPrintCallStack(void* fileHandle)
118 {
119     std::stringstream s;
120     cmajor::rt::CallStack* callStack = cmajor::rt::callStack;
121     if (!callStack)
122     {
123         callStack = new cmajor::rt::CallStack();
124         cmajor::rt::callStack = callStack;
125     }
126     s << "CALL STACK:\n";
127     int n = callStack->Locations().size();
128     for (int i = n - 1; i >= 0; --i)
129     {
130         const cmajor::rt::SourceLocation& location = callStack->Locations()[i];
131         s << location.functionName << " " << location.sourceFilePath << ":" << location.lineNumber << "\n";
132     }
133     std::string str = s.str();
134     int32_t errorStringHandle = -1;
135     RtWrite(fileHandle, reinterpret_cast<const uint8_t*>(str.c_str()), str.length(), errorStringHandle);
136     RtFlush(fileHandle, errorStringHandle);
137 }
138 
139 extern "C" const char* RtGetStackTrace()
140 {
141     std::stringstream s;
142     cmajor::rt::CallStack* callStack = cmajor::rt::callStack;
143     if (!callStack)
144     {
145         callStack = new cmajor::rt::CallStack();
146         cmajor::rt::callStack = callStack;
147     }
148     int n = callStack->Locations().size();
149     for (int i = n - 1; i >= 0; --i)
150     {
151         const cmajor::rt::SourceLocation& location = callStack->Locations()[i];
152         s << location.functionName << " " << location.sourceFilePath << ":" << location.lineNumber << "\n";
153     }
154     cmajor::rt::stackTrace = new std::string(s.str());
155     return cmajor::rt::stackTrace->c_str();
156 }
157 
158 extern "C" void RtDisposeStackTrace()
159 {
160     delete cmajor::rt::stackTrace;
161 }