Add DaliPrintBackTrace for common
[platform/core/uifw/dali-core.git] / dali / public-api / common / dali-common.cpp
1 /*
2  * Copyright (c) 2023 Samsung Electronics Co., Ltd.
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
18 // CLASS HEADER
19 #include <dali/public-api/common/dali-common.h>
20
21 // EXTERNAL INCLUDES
22 #include <stdlib.h>
23 #include <cstdio>
24 #include <string>
25
26 #if defined(BACKTRACE_ENABLED)
27 #if defined(__GLIBC__)
28 #include <execinfo.h>
29 #endif
30 #include <cxxabi.h>
31 #endif
32 #include <cstring>
33
34 // INTERNAL INCLUDES
35 #include <dali/integration-api/debug.h>
36
37 namespace Dali
38 {
39 #if defined(BACKTRACE_ENABLED)
40
41 namespace
42 {
43 const int32_t MAX_NUM_STACK_FRAMES = 25;
44 }
45
46 std::string Demangle(const char* symbol)
47 {
48   std::string result;
49
50   // backtrace ::=  <filename>'('['_'<mangled-symbol>'_']['+'<offset>]')'
51   // Only want <mangled-symbol>:
52   const char* openParen = strchr(symbol, '(');
53   if(openParen != NULL)
54   {
55     const char* startOfToken = openParen + 1;
56     const char* plus         = strchr(startOfToken, '+');
57     const char* closeParen   = strchr(startOfToken, ')');
58     const char* endOfToken   = NULL;
59     if(plus != NULL)
60     {
61       endOfToken = plus;
62     }
63     else if(closeParen != NULL)
64     {
65       endOfToken = closeParen;
66     }
67     if(endOfToken != NULL)
68     {
69       size_t tokenLength = endOfToken - startOfToken;
70
71       // Allocate space for symbol
72       char* mangledSymbol = reinterpret_cast<char*>(malloc(tokenLength + 1u));
73       if(mangledSymbol != NULL)
74       {
75         strncpy(mangledSymbol, startOfToken, tokenLength);
76         mangledSymbol[tokenLength] = '\0';
77
78         size_t  size;
79         int32_t status;
80         char*   demangled = NULL;
81         demangled         = abi::__cxa_demangle(mangledSymbol, NULL, &size, &status);
82         if(demangled != NULL)
83         {
84           result = demangled;
85           free(demangled); // demangle() allocates returned string, so free it
86         }
87         else
88         {
89           result = symbol;
90         }
91         free(mangledSymbol);
92       }
93     }
94   }
95
96   return result;
97 }
98
99 DALI_CORE_API DaliException::DaliException(const char* location, const char* condition)
100 : location(location),
101   condition(condition)
102 {
103   // Note, if a memory error has occured, then the backtrace won't work - backtrace_symbols relies on
104   // allocating memory.
105
106   // Initial dlog error message is output in DALI_ASSERT_ALWAYS macro
107   // Also output on stderr
108 #if defined(DEBUG_ENABLED)
109   fprintf(stderr, "Exception: \n%s\n thrown at %s\nSee dlog for backtrace\n", condition, location);
110 #else
111   fprintf(stderr, "Exception: \n%s\n thrown\nSee dlog for backtrace\n", condition);
112 #endif
113
114   DALI_LOG_ERROR_NOFN("Backtrace:\n");
115
116   void*   frameArray[MAX_NUM_STACK_FRAMES];
117   int32_t nSize   = backtrace(frameArray, MAX_NUM_STACK_FRAMES);
118   char**  symbols = backtrace_symbols(frameArray, nSize);
119   for(int32_t i = 1; i < nSize; i++)
120   {
121     std::string demangled_symbol = Demangle(symbols[i]);
122     DALI_LOG_ERROR_NOFN("[%02d]   %s\n", i, demangled_symbol.c_str());
123   }
124   free(symbols);
125 }
126
127 DALI_CORE_API void DaliPrintBackTrace()
128 {
129   DALI_LOG_ERROR_NOFN("Backtrace:\n");
130
131   void*   frameArray[MAX_NUM_STACK_FRAMES];
132   int32_t nSize   = backtrace(frameArray, MAX_NUM_STACK_FRAMES);
133   char**  symbols = backtrace_symbols(frameArray, nSize);
134   for(int32_t i = 1; i < nSize; i++)
135   {
136     std::string demangled_symbol = Demangle(symbols[i]);
137     DALI_LOG_ERROR_NOFN("[%02d]   %s\n", i, demangled_symbol.c_str());
138   }
139   free(symbols);
140 }
141
142 #else // BACKTRACE_ENABLED
143
144 DALI_CORE_API DaliException::DaliException(const char* location, const char* condition)
145 : location(location),
146   condition(condition)
147 {
148 #if defined(DEBUG_ENABLED)
149   printf("Exception: \n%s\n thrown at %s\n", condition, location);
150 #else
151   printf("Exception: \n%s\n thrown\n", condition);
152 #endif
153 }
154
155 DALI_CORE_API void DaliPrintBackTrace()
156 {
157 }
158
159 #endif // BACKTRACE_ENABLED
160
161 DALI_CORE_API void DaliAssertMessage(const char* location, const char* condition)
162 {
163 #if defined(DEBUG_ENABLED)
164   DALI_LOG_ERROR_NOFN("Assert (%s) failed in: %s\n", condition, location);
165 #else
166   DALI_LOG_ERROR_NOFN("Assert (%s) failed\n", condition);
167 #endif
168 }
169
170 } // namespace Dali