ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/development/src/debug/Debugger.cpp
Revision: 1490
Committed: Fri Aug 13 15:02:28 2010 UTC (14 years, 8 months ago) by chuckv
File size: 5430 byte(s)
Log Message:
Adding some error reporting and debuging code to OpenMD. This code is borrowed from ProtoMol.

File Contents

# Content
1 /*******************************************************************\
2
3 Copyright (C) 2004 Joseph Coffland
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but 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, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18 02111-1307, USA.
19
20 For information regarding this software email
21 jcofflan@users.sourceforge.net
22
23 \*******************************************************************/
24
25 #include <protomol/base/Exception.h>
26
27 #ifdef HAVE_DEBUGGER
28 #include <protomol/debug/Debugger.h>
29 #include <protomol/debug/Process.h>
30 #include <protomol/type/String.h>
31
32 #include <sys/time.h>
33 #include <sys/resource.h>
34 #include <unistd.h>
35 #include <sys/types.h>
36 #include <sys/wait.h>
37 #include <sys/stat.h>
38 #include <fcntl.h>
39 #include <stdlib.h>
40 #include <stdio.h>
41
42 #include <sstream>
43
44 using namespace std;
45 using namespace ProtoMol;
46
47 string Debugger::executableName;
48 int Debugger::numTraces = 0;
49 bool Debugger::traceFiltering = true;
50 int Debugger::maxTraces = 10;
51
52 void Debugger::initStackTrace(string executableName) {
53 Debugger::executableName = executableName;
54 Exception::enableStackTraces = true;
55 }
56
57 bool Debugger::printStackTrace(ostream &stream) {
58 trace_t trace;
59 bool retVal = getStackTrace(trace);
60
61 trace_t::iterator it;
62 for (it = trace.begin(); it != trace.end(); it++)
63 stream << *it << endl;
64
65 return retVal;
66 }
67
68 #define BUF_SIZE 2048
69
70 bool Debugger::_getStackTrace(trace_t &trace) {
71 if (executableName == "") {
72 trace.push_back("Stack Trace Error: Stack dumper not initialized!");
73 return false;
74 }
75
76 numTraces++;
77 if (maxTraces && numTraces > maxTraces) {
78 trace.push_back("Stack Trace Error: Exceeded maxTraces of " +
79 String(maxTraces));
80 return false;
81 }
82
83 // Spawn gdb process
84 int argc = 0;
85 const char *argv[5];
86
87 argv[argc++] = "gdb";
88 argv[argc++] = (char *)executableName.c_str();
89 String pid(getpid());
90 argv[argc++] = (char *)pid.c_str();
91 argv[argc] = 0;
92
93 try {
94 Process debugProc;
95 Pipe *inPipe = debugProc.getChildPipe(Process::TO_CHILD, 0);
96 Pipe *outPipe = debugProc.getChildPipe(Process::FROM_CHILD, 1);
97 Pipe *errPipe = debugProc.getChildPipe(Process::FROM_CHILD, 2);
98
99 // Run gdb commands
100 string debugCmd =
101 string("set width ") + String(BUF_SIZE - 1) + "\nwhere\nquit\n";
102 ssize_t size =
103 write(inPipe->getInFD(), debugCmd.c_str(), debugCmd.length());
104 size = size;
105
106 // Execute debugger process
107 debugProc.exec((char **)argv);
108
109 // Read output
110 FILE *out = fdopen(outPipe->getOutFD(), "r");
111 FILE *err = fdopen(errPipe->getOutFD(), "r");
112 if (!out || !err) {
113 trace.push_back("Stack Trace Error: Opening debugger output streams!");
114
115 return false;
116 }
117
118 char buf[BUF_SIZE + 1];
119 int offset = 0;
120 int count = 0;
121 while (fgets(buf, BUF_SIZE, out))
122 if (buf[0] == '#') {
123 if (traceFiltering) {
124 count++;
125
126 if (strstr(buf, "Debugger::") ||
127 strstr(buf, "Exception::init") ||
128 strstr(buf, "Exception (")) {
129 offset = count;
130 trace.clear();
131 continue;
132 }
133 }
134
135 int line = atoi(&buf[1]) - offset;
136 char *start = strchr(buf, ' ');
137 int len = strlen(buf);
138
139 if (buf[len - 1] == '\n' || buf[len - 1] == '\r') buf[len - 1] = 0;
140 trace.push_back(string("#") + String(line) + start);
141 }
142
143 #ifdef DEBUGGER_PRINT_ERROR_STREAM
144 while (fgets(buf, BUF_SIZE, err)) {
145 int len = strlen(buf);
146 if (buf[len - 1] == '\n' || buf[len - 1] == '\r') buf[len - 1] = 0;
147 if (buf[0] != 0) trace.push_back(buf);
148 }
149 #endif
150
151
152 // Clean up
153 fclose(out);
154 fclose(err);
155
156 debugProc.wait();
157 if (debugProc.getReturnCode()) {
158 trace.push_back("Stack Trace Error: gdb returned an error.");
159
160 return false;
161 }
162
163 return true;
164 } catch (const Exception &e) {
165 trace.push_back(string("Stack Trace Error: ") + e.getMessage());
166 }
167
168 return false;
169 }
170
171 bool Debugger::getStackTrace(trace_t &trace) {
172 static bool inStackTrace = false;
173 bool ret;
174
175 if (inStackTrace) {
176 trace.push_back("Stack Trace Error: Already in stack trace!");
177 return false;
178 }
179
180 inStackTrace = true;
181
182 try {
183 ret = _getStackTrace(trace);
184 } catch (...) {
185 inStackTrace = false;
186 throw;
187 }
188 inStackTrace = false;
189
190 return ret;
191 }
192 #endif // HAVE_DEBUGGER
193
194 #ifdef DEBUGGER_TEST
195 #include <iostream>
196
197 void b(int x) {
198 THROW("Test cause!");
199 }
200
201 void a(char *x) {
202 try {
203 b(10);
204 } catch (const Exception &e) {
205 THROWC("Test exception!", e);
206 }
207 }
208
209 int main(int argc, char *argv[]) {
210 Debugger::initStackTrace(argv[0]);
211
212 try {
213 a("test");
214 } catch (const Exception &e) {
215 cerr << "Exception: " << e << endl;
216 }
217
218 return 0;
219 }
220
221 #endif // DEBUGGER_TEST