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 #include <execinfo.h>
28 #include <cxxabi.h>
29 #include <dlfcn.h>
30 
31 #include <cstdio>
32 #include <cstdlib>
33 #include <sstream>
34 
35 #include <IceUtil/Exception.h>
37 #include <Ice/LocalException.h>
40 
41 
42 namespace armarx
43 {
44  LocalException::LocalException() :
45  reason(""),
46  backtrace(""),
47  output_buffer("")
48  {
49  backtrace = std::runtime_error(generateBacktrace());
50  setReason("");
51  }
52 
53  LocalException::LocalException(const LocalException& e) noexcept:
54  reason(e.reason), backtrace(e.backtrace), output_buffer("")
55  {
56  }
57 
58  void LocalException::setReason(const std::string& r)
59  {
60  this->reason = std::runtime_error(r);
61  }
62 
63  std::string LocalException::getReason() const
64  {
65  return reason.what();
66  }
67 
68  const char* LocalException::what() const noexcept
69  {
70  // TODO: generateOutputString is not noexcept and changes the state of the exception
71  output_buffer = std::runtime_error(generateOutputString());
72 
73  return output_buffer.what();
74  }
75 
76  std::string LocalException::generateBacktrace()
77  {
78  int skip = 3;
79  void* callstack[128];
80  const int nMaxFrames = sizeof(callstack) / sizeof(callstack[0]);
81  char buf[1024];
82 
83  int nFrames = ::backtrace(callstack, nMaxFrames);
84  char** symbols = backtrace_symbols(callstack, nFrames);
85 
86  std::ostringstream trace_buf;
87 
88  for (int i = skip; i < nFrames; i++)
89  {
90  Dl_info info;
91 
92  if (dladdr(callstack[i], &info) && info.dli_sname)
93  {
94  char* demangled = nullptr;
95  int status = -1;
96 
97  if (info.dli_sname[0] == '_')
98  {
99  demangled = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status);
100  }
101 
102  snprintf(buf, sizeof(buf), "%-3d %*p %s + %zd\n",
103  i - skip + 1, int(2 + sizeof(void*) * 2), callstack[i],
104  status == 0 ? demangled :
105  info.dli_sname == nullptr ? symbols[i] : info.dli_sname,
106  (char*)callstack[i] - (char*)info.dli_saddr);
107  free(demangled);
108  }
109  else
110  {
111  snprintf(buf, sizeof(buf), "%-3d %*p %s\n",
112  i - skip + 1, int(2 + sizeof(void*) * 2), callstack[i], symbols[i]);
113  }
114 
115  trace_buf << buf;
116  }
117 
118  free(symbols);
119 
120  if (nFrames == nMaxFrames)
121  {
122  trace_buf << "[truncated]\n";
123  }
124 
125  return trace_buf.str();
126  }
127 
128  std::string LocalException::generateOutputString() const
129  {
130  // TODO: this is not noexcept
131  std::stringstream what_buf;
132 
133  what_buf << std::endl;
134  what_buf << "Reason: " << ((strlen(reason.what()) == 0) ? "undefined" : reason.what()) << std::endl;
135  what_buf << "Backtrace: " << std::endl;
136  what_buf << backtrace.what() << std::endl;
137 
138  return what_buf.str();
139  }
140 
142  {
143  *((ARMARX_LOG_S) .setBacktrace(false)) << armarx::MessageTypeT::ERROR << GetHandledExceptionString();
145  }
146 
148  {
149  std:: stringstream result;
150 
151  try
152  {
153  throw;
154  }
155  catch (const UserException& userException)
156  {
157  // Handle marshallable user exceptions
158  result
159  << "Caught userException: " << userException.what() << "\n"
160  << "\tReason: " << userException.reason << "\n"
161  << "\tStacktrace: \n" << userException.ice_stackTrace();
162 
163  }
164 
165 
166 
167  catch (const LocalException& exception)
168  {
169  // Handle local (run-time) exceptions
170  result
171  << "Caught " << exception.name() << ":\n" << exception.what()
172  ;
173  }
174 
175  catch (const Ice::NoValueFactoryException& e)
176  {
177  std::stringstream availableFactories;
178 
179  for (const auto& elem : FactoryCollectionBase::GetPreregistratedFactories())
180  {
181  ObjectFactoryMap objFacMap = elem->getFactories();
182  ObjectFactoryMap::iterator it = objFacMap.begin();
183 
184  for (; it != objFacMap.end(); it++)
185  {
186  availableFactories << "\t" << it->first;
187  availableFactories << "\n";
188  }
189  }
190 
191  auto typePart = e.type.substr(e.type.find_last_of(':') + 1);
192 
193  result
194  << "Caught NoObjectFactoryException:\n " << e.what()
195  << "\n\nPossible reasons:\n"
196  << "\t- You did not link the library where the object factory is declared\n"
197  << "\t- You did not include the header of the object factory\n\n"
198  << "\tThese object factories are usually located in header files called XYZObjectFactories.h. This header file needs to be included into your library."
199  << "Additionally, also the library needs to be included. To find these file you can try the following command (linux):\n"
200  << "\tgrep -r \"" << typePart << "\" ~/armarx/ --include \"*Factor*\"\n"
201  << "\t Include that header file and find out to which libray this header belongs (usually the CMakeLists.txt next to it) and link this lib to your library."
202  << "\n\nAvailable factories: \n" << availableFactories.str()
203  // << "\nBacktrace: " << exception.ice_stackTrace()
204  ;
205  }
206  catch (const Ice::UnexpectedObjectException& e)
207  {
208  std::stringstream availableFactories;
209 
210  for (const auto& elem : FactoryCollectionBase::GetPreregistratedFactories())
211  {
212  ObjectFactoryMap objFacMap = elem->getFactories();
213  ObjectFactoryMap::iterator it = objFacMap.begin();
214 
215  for (; it != objFacMap.end(); it++)
216  {
217  availableFactories << "\t" << it->first;
218  availableFactories << "\n";
219  }
220  }
221 
222  auto typePart = e.expectedType.substr(e.expectedType.find_last_of(':') + 1);
223 
224  result
225  << "Caught UnexpectedObjectException:\n " << e.what()
226  << "\n\nPossible reasons:\n"
227  << "\t- You did not link the library where the object factory is declared\n"
228  << "\t- You did not include the header of the object factory\n\n"
229  << "\tThese object factories are usually located in header files called XYZObjectFactories.h. This header file needs to be included into your library."
230  << "Additionally, also the library needs to be included. To find these file you can try the following command (linux):\n"
231  << "\tgrep -r \"" << typePart << "\" ~/armarx/ --include \"*Factor*\"\n"
232  << "\t Include that header file and find out to which libray this header belongs (usually the CMakeLists.txt next to it) and link this lib to your library."
233  << "\n\nAvailable factories: \n" << availableFactories.str()
234  // << "\nBacktrace: " << exception.ice_stackTrace()
235  ;
236  }
237 
238  catch (const Ice::OperationNotExistException& e)
239  {
240  result
241  << "\033[1mCaught OperationNotExistException:\n " << e.what()
242  << "\n\nPossible reasons:\n"
243  << "\t- You are using a topic instead of offering a topic (usingTopic(name): receive data, offeringTopic(name): provide data) \n"
245  }
246 
247  catch (const IceUtil::Exception& exception)
248  {
249 
250  result
251  << "Caught IceUtil::Exception:\n " << exception.what()
252  << "\nBacktrace: " << exception.ice_stackTrace()
253  ;
254  }
255  catch (const std::exception& exception)
256  {
257 
258  result
259  << "Caught std::exception:\n" << exception.what()
260  ;
261  }
262  catch (...)
263  {
264  result
265  << "Caught unknown exception!"
266  ;
267  }
268  result << "\nTrace created by calling ARMARX_TRACE:\n";
270  return result.str();
271  }
272 }
armarx::MessageTypeT::ERROR
@ ERROR
armarx::FactoryCollectionBase::GetPreregistratedFactories
static const std::vector< FactoryCollectionBasePtr > & GetPreregistratedFactories()
Definition: FactoryCollectionBase.h:73
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:61
armarx::GetHandledExceptionString
std::string GetHandledExceptionString()
Definition: Exception.cpp:147
armarx::status
status
Definition: FiniteStateMachine.h:259
ARMARX_LOG_S
#define ARMARX_LOG_S
Definition: Logging.h:145
Logging.h
armarx::handleExceptions
void handleExceptions()
Definition: Exception.cpp:141
armarx::detail::Trace::ClearExceptionBacktrace
static void ClearExceptionBacktrace()
Definition: trace.cpp:90
armarx::detail::Trace::PrintExceptionBacktrace
static void PrintExceptionBacktrace(std::ostream &out, const std::string &pre="")
Definition: trace.cpp:195
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:28
armarx::LogSender::eReset
@ eReset
Definition: LogSender.h:71
Exception.h