Exception.cpp
Go to the documentation of this file.
1 /*
2 * This file is part of ArmarX.
3 *
4 * Copyright (C) 2011-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5 *
6 * ArmarX is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * ArmarX is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * @package ArmarXCore::core
19 * @author Jan Issac (jan dot issac at gmx dot de)
20 * @author Kai Welke (welke at kit dot edu)
21 * @date 2011
22 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
23 * GNU General Public License
24 */
25 
26 #include "Exception.h"
27 
28 #include <cstdio>
29 #include <cstdlib>
30 #include <sstream>
31 
32 #include <dlfcn.h>
33 
34 #include <Ice/LocalException.h>
35 #include <IceUtil/Exception.h>
36 
40 
41 #include <cxxabi.h>
42 #include <execinfo.h>
43 
44 namespace armarx
45 {
46  LocalException::LocalException() : reason(""), backtrace(""), output_buffer("")
47  {
48  backtrace = std::runtime_error(generateBacktrace());
49  setReason("");
50  }
51 
52  LocalException::LocalException(const LocalException& e) noexcept :
53  reason(e.reason), backtrace(e.backtrace), output_buffer("")
54  {
55  }
56 
57  void
58  LocalException::setReason(const std::string& r)
59  {
60  this->reason = std::runtime_error(r);
61  }
62 
63  std::string
64  LocalException::getReason() const
65  {
66  return reason.what();
67  }
68 
69  const char*
70  LocalException::what() const noexcept
71  {
72  // TODO: generateOutputString is not noexcept and changes the state of the exception
73  output_buffer = std::runtime_error(generateOutputString());
74 
75  return output_buffer.what();
76  }
77 
78  std::string
79  LocalException::generateBacktrace()
80  {
81  int skip = 3;
82  void* callstack[128];
83  const int nMaxFrames = sizeof(callstack) / sizeof(callstack[0]);
84  char buf[1024];
85 
86  int nFrames = ::backtrace(callstack, nMaxFrames);
87  char** symbols = backtrace_symbols(callstack, nFrames);
88 
89  std::ostringstream trace_buf;
90 
91  for (int i = skip; i < nFrames; i++)
92  {
93  Dl_info info;
94 
95  if (dladdr(callstack[i], &info) && info.dli_sname)
96  {
97  char* demangled = nullptr;
98  int status = -1;
99 
100  if (info.dli_sname[0] == '_')
101  {
102  demangled = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status);
103  }
104 
105  snprintf(buf,
106  sizeof(buf),
107  "%-3d %*p %s + %zd\n",
108  i - skip + 1,
109  int(2 + sizeof(void*) * 2),
110  callstack[i],
111  status == 0 ? demangled
112  : info.dli_sname == nullptr ? symbols[i]
113  : info.dli_sname,
114  (char*)callstack[i] - (char*)info.dli_saddr);
115  free(demangled);
116  }
117  else
118  {
119  snprintf(buf,
120  sizeof(buf),
121  "%-3d %*p %s\n",
122  i - skip + 1,
123  int(2 + sizeof(void*) * 2),
124  callstack[i],
125  symbols[i]);
126  }
127 
128  trace_buf << buf;
129  }
130 
131  free(symbols);
132 
133  if (nFrames == nMaxFrames)
134  {
135  trace_buf << "[truncated]\n";
136  }
137 
138  return trace_buf.str();
139  }
140 
141  std::string
142  LocalException::generateOutputString() const
143  {
144  // TODO: this is not noexcept
145  std::stringstream what_buf;
146 
147  what_buf << std::endl;
148  what_buf << "Reason: " << ((strlen(reason.what()) == 0) ? "undefined" : reason.what())
149  << std::endl;
150  what_buf << "Backtrace: " << std::endl;
151  what_buf << backtrace.what() << std::endl;
152 
153  return what_buf.str();
154  }
155 
156  void
158  {
159  *((ARMARX_LOG_S).setBacktrace(false))
162  }
163 
164  std::string
166  {
167  std::stringstream result;
168 
169  try
170  {
171  throw;
172  }
173  catch (const UserException& userException)
174  {
175  // Handle marshallable user exceptions
176  result << "Caught userException: " << userException.what() << "\n"
177  << "\tReason: " << userException.reason << "\n"
178  << "\tStacktrace: \n"
179  << userException.ice_stackTrace();
180  }
181 
182 
183  catch (const LocalException& exception)
184  {
185  // Handle local (run-time) exceptions
186  result << "Caught " << exception.name() << ":\n" << exception.what();
187  }
188 
189  catch (const Ice::NoValueFactoryException& e)
190  {
191  std::stringstream availableFactories;
192 
193  for (const auto& elem : FactoryCollectionBase::GetPreregistratedFactories())
194  {
195  ObjectFactoryMap objFacMap = elem->getFactories();
196  ObjectFactoryMap::iterator it = objFacMap.begin();
197 
198  for (; it != objFacMap.end(); it++)
199  {
200  availableFactories << "\t" << it->first;
201  availableFactories << "\n";
202  }
203  }
204 
205  auto typePart = e.type.substr(e.type.find_last_of(':') + 1);
206 
207  result
208  << "Caught NoObjectFactoryException:\n " << e.what() << "\n\nPossible reasons:\n"
209  << "\t- You did not link the library where the object factory is declared\n"
210  << "\t- You did not include the header of the object factory\n\n"
211  << "\tThese object factories are usually located in header files called "
212  "XYZObjectFactories.h. This header file needs to be included into your library."
213  << "Additionally, also the library needs to be included. To find these file you "
214  "can try the following command (linux):\n"
215  << "\tgrep -r \"" << typePart << "\" ~/armarx/ --include \"*Factor*\"\n"
216  << "\t Include that header file and find out to which libray this header belongs "
217  "(usually the CMakeLists.txt next to it) and link this lib to your library."
218  << "\n\nAvailable factories: \n"
219  << availableFactories.str()
220  // << "\nBacktrace: " << exception.ice_stackTrace()
221  ;
222  }
223  catch (const Ice::UnexpectedObjectException& e)
224  {
225  std::stringstream availableFactories;
226 
227  for (const auto& elem : FactoryCollectionBase::GetPreregistratedFactories())
228  {
229  ObjectFactoryMap objFacMap = elem->getFactories();
230  ObjectFactoryMap::iterator it = objFacMap.begin();
231 
232  for (; it != objFacMap.end(); it++)
233  {
234  availableFactories << "\t" << it->first;
235  availableFactories << "\n";
236  }
237  }
238 
239  auto typePart = e.expectedType.substr(e.expectedType.find_last_of(':') + 1);
240 
241  result
242  << "Caught UnexpectedObjectException:\n " << e.what() << "\n\nPossible reasons:\n"
243  << "\t- You did not link the library where the object factory is declared\n"
244  << "\t- You did not include the header of the object factory\n\n"
245  << "\tThese object factories are usually located in header files called "
246  "XYZObjectFactories.h. This header file needs to be included into your library."
247  << "Additionally, also the library needs to be included. To find these file you "
248  "can try the following command (linux):\n"
249  << "\tgrep -r \"" << typePart << "\" ~/armarx/ --include \"*Factor*\"\n"
250  << "\t Include that header file and find out to which libray this header belongs "
251  "(usually the CMakeLists.txt next to it) and link this lib to your library."
252  << "\n\nAvailable factories: \n"
253  << availableFactories.str()
254  // << "\nBacktrace: " << exception.ice_stackTrace()
255  ;
256  }
257 
258  catch (const Ice::OperationNotExistException& e)
259  {
260  result << "\033[1mCaught OperationNotExistException:\n " << e.what()
261  << "\n\nPossible reasons:\n"
262  << "\t- You are using a topic instead of offering a topic (usingTopic(name): "
263  "receive data, offeringTopic(name): provide data) \n"
265  }
266 
267  catch (const IceUtil::Exception& exception)
268  {
269 
270  result << "Caught IceUtil::Exception:\n " << exception.what()
271  << "\nBacktrace: " << exception.ice_stackTrace();
272  }
273  catch (const std::exception& exception)
274  {
275 
276  result << "Caught std::exception:\n" << exception.what();
277  }
278  catch (...)
279  {
280  result << "Caught unknown exception!";
281  }
282  result << "\nTrace created by calling ARMARX_TRACE:\n";
284  return result.str();
285  }
286 } // namespace armarx
armarx::MessageTypeT::ERROR
@ ERROR
armarx::FactoryCollectionBase::GetPreregistratedFactories
static const std::vector< FactoryCollectionBasePtr > & GetPreregistratedFactories()
Definition: FactoryCollectionBase.h:76
armarx::LogSender::GetColorCodeString
static std::string GetColorCodeString(MessageTypeT verbosityLevel)
Definition: LogSender.cpp:300
trace.h
FactoryCollectionBase.h
armarx::ObjectFactoryMap
std::map< std::string, Ice::ValueFactoryPtr > ObjectFactoryMap
Definition: FactoryCollectionBase.h:62
armarx::GetHandledExceptionString
std::string GetHandledExceptionString()
Definition: Exception.cpp:165
armarx::status
status
Definition: FiniteStateMachine.h:244
ARMARX_LOG_S
#define ARMARX_LOG_S
Definition: Logging.h:145
Logging.h
armarx::handleExceptions
void handleExceptions()
Definition: Exception.cpp:157
armarx::detail::Trace::ClearExceptionBacktrace
static void ClearExceptionBacktrace()
Definition: trace.cpp:100
armarx::detail::Trace::PrintExceptionBacktrace
static void PrintExceptionBacktrace(std::ostream &out, const std::string &pre="")
Definition: trace.cpp:216
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:27
armarx::LogSender::eReset
@ eReset
Definition: LogSender.h:70
Exception.h