root/trunk/whisperlib/common/base/system.cc

Revision 7, 7.9 kB (checked in by whispercastorg, 2 years ago)

version 0.2.0

Line 
1 // Copyright (c) 2009, Whispersoft s.r.l.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Whispersoft s.r.l. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 //
30 // Author: Cosmin Tudorache & Catalin Popescu
31
32 #include "common/base/system.h"
33
34 #include <stdlib.h>
35 #include <execinfo.h>
36 #include <stdio.h>
37
38 #ifndef _NO_BFD
39 #include <bfd.h>
40 #include <cxxabi.h>
41 #endif
42
43 #include <string>
44
45 #include "common/base/log.h"
46 #include "common/base/signal_handlers.h"
47 #include "common/base/strutil.h"
48 #include "common/base/gflags.h"
49
50
51 //////////////////////////////////////////////////////////////////////
52
53 DEFINE_bool(loop_on_exit,
54             false,
55             "If this is turned on, we loop on exit waiting for your debuger");
56
57 DEFINE_bool(loop_on_crash,
58             false,
59             "Causes the program to hang on bad signals waiting for "
60             "your debugger.");
61
62 //////////////////////////////////////////////////////////////////////
63
64 namespace {
65
66 static char* bfd_filename;
67
68 #ifdef _NO_BFD
69
70 bool DecodeBacktrace(const vector<string>& addr,
71                      vector<string>* ret) {
72   ret->push_back(string("For Stacktrace run this (cut and paste): "));
73   ret->push_back(string("addr2line -e ") + bfd_filename + " \\");
74   for ( size_t i = 0; i < addr.size(); i++ ) {
75     ret->push_back(strutil::StringPrintf("%s \\", addr[i].c_str()));
76   }
77   ret->push_back("");
78   return true;
79 }
80
81 #else
82
83 static void* SlurpSymtab(bfd* abfd) {
84   int64 symcount;
85   // size_t size;
86   unsigned int size;
87   if ( (bfd_get_file_flags(abfd) & HAS_SYMS) == 0 ) {
88     return false;
89   }
90   void* syms = NULL;
91   symcount = bfd_read_minisymbols(abfd, false, &syms, &size);
92   if ( symcount == 0 ) {
93     // true -> dynamic
94     symcount = bfd_read_minisymbols(abfd, true, &syms, &size);
95   }
96   if ( symcount < 0 ) {
97     return NULL;
98   }
99   return syms;
100 }
101
102 struct ScanData {
103   asymbol** syms;
104   bfd_vma pc;
105   bfd_boolean found;
106   const char* filename;
107   const char* functionname;
108   unsigned int line;
109 };
110
111
112 static void FindAddressInSection(bfd* abfd,
113                                  asection* section,
114                                  void* data) {
115   ScanData* sd = reinterpret_cast<ScanData*>(data);
116   bfd_vma vma;
117   bfd_size_type size;
118   if ( sd->found )
119     return;
120   if ( (bfd_get_section_flags(abfd, section) & SEC_ALLOC) == 0 )
121     return;
122   vma = bfd_get_section_vma(abfd, section);
123   if ( sd->pc < vma )
124     return;
125   size = bfd_get_section_size(section);
126   if ( sd->pc >= vma + size )
127     return;
128   sd->found = bfd_find_nearest_line(
129     abfd, section, sd->syms, sd->pc - vma,
130     &sd->filename, &sd->functionname, &sd->line);
131 }
132
133 static void TranslateAddresses(bfd* abfd,
134                                asymbol** syms,
135                                const vector<string>& addr,
136                                vector<string>* ret) {
137   ScanData sd;
138   sd.syms = syms;
139   for ( size_t i = 0; i < addr.size(); i++ ) {
140     sd.found = false;
141     sd.pc = bfd_scan_vma(addr[i].c_str(), NULL, 16);
142     bfd_map_over_sections(abfd, FindAddressInSection, &sd);
143     string fileline;
144     string function;
145     if ( !sd.found ) {
146       fileline = "??:0";
147       function = "??";
148     } else {
149       if ( sd.functionname == NULL || *sd.functionname == '\0' ) {
150         function = "??";
151       } else {
152         char buff[1024];
153         size_t len = sizeof(buff);
154         memset(buff, 0, len);
155         int status;
156         __cxxabiv1::__cxa_demangle(sd.functionname, buff, &len, &status);
157         if ( *buff ) {
158           function = buff;
159         } else {
160           function = sd.functionname;
161         }
162       }
163       fileline = strutil::StringPrintf(
164         "[ %80s ]",
165         strutil::StringPrintf("%s:%d",
166                               (sd.filename ? sd.filename : "??"),
167                               static_cast<int>(sd.line)).c_str());
168       ret->push_back(fileline + " - " + function);
169     }
170   }
171 }
172
173 bool DecodeBacktrace(const vector<string>& addr,
174                      vector<string>* ret) {
175   char** matching;
176   bfd* abfd = bfd_openr(bfd_filename, NULL);
177
178   if ( abfd == NULL )
179     return false;
180   if ( bfd_check_format(abfd, bfd_archive) )
181     return false;
182
183   if ( !bfd_check_format_matches(abfd, bfd_object, &matching) )
184     return false;
185   asymbol** syms =  reinterpret_cast<asymbol**>(SlurpSymtab(abfd));
186   if ( syms == NULL ) {
187     return false;
188   }
189   TranslateAddresses(abfd, syms, addr, ret);
190
191   if ( syms != NULL )
192     free(syms);
193   return true;
194 }
195 #endif  // _NO_BFD
196 }
197
198 namespace common {
199
200 void InternalSystemExit(int error) {
201   if ( FLAGS_loop_on_exit ) {
202     while ( true ) {
203       if ( log_internal::gLogger != NULL )
204         LOG_INFO << " Looping on exit - attach to us !";
205       FlushLogger();
206       sleep(40);
207     }
208   }
209   if ( log_internal::gLogger != NULL )
210     LOG_INFO << " Exiting with error : " << error;
211   FlushLogger();
212 }
213
214 void InternalSystemAtExit() {
215   if ( log_internal::gLogger != NULL )
216     delete log_internal::gLogger;
217   log_internal::gLogger = NULL;
218 }
219
220
221 // This is used by the unittest to test error-exit code
222 int Exit(int error, bool forced) {
223   FlushLogger();
224   if ( forced ) {
225     // forcefully exit, avoiding any destructor/atexit()/etc calls
226     cerr << "Forcefully exiting with error: " << error << endl;
227     ::_exit(error);
228   } else {
229     InternalSystemExit(error);
230     ::exit(error);
231   }
232   // keep things simple in main()...
233   return error;
234 }
235
236 void Init(int argc, char* argv[]) {
237   bfd_filename = strdup(argv[0]);
238   string full_command(
239     strutil::JoinStrings(const_cast<const char**>(argv), argc, " "));
240   char cwd[2048] = { 0, };
241   fprintf(stderr, "CWD: [%s] CMD: [%s]\n",
242           getcwd(cwd, sizeof(cwd)), full_command.c_str());
243   google::ParseCommandLineFlags(&argc, &argv, true);
244   InitDefaultLogger(strutil::Basename(argv[0]));
245
246 #ifndef _NO_BFD
247   bfd_init();
248 #endif
249
250   LOG_INFO << "Started : " << argv[0];
251   CHECK(InstallDefaultSignalHandlers(FLAGS_loop_on_crash));
252   LOG_INFO << "Command Line: " << full_command;
253   atexit(&InternalSystemAtExit);
254 }
255
256 string GetBacktrace() {
257   void* trace[100];
258   const int trace_size = backtrace(trace, sizeof(trace) / sizeof(*trace));
259   vector<string> addrs;
260   vector<string> fitered_messages;
261   for ( int i = 0; i < trace_size; i++ ) {
262     addrs.push_back(strutil::StringPrintf(
263                         "0x%lx",
264                         reinterpret_cast<unsigned long int>(trace[i])));
265   }
266   DecodeBacktrace(addrs, &fitered_messages);
267   return strutil::JoinStrings(fitered_messages, "\n");
268 }
269
270 const char* ByteOrderName(ByteOrder order) {
271   switch ( order ) {
272     CONSIDER(BIGENDIAN);
273     CONSIDER(LILENDIAN);
274   default: LOG_FATAL << " Unsupported byte order: " << order;
275   }
276   return "Unknown";
277 }
278
279 }   // end namespace system
Note: See TracBrowser for help on using the browser.