1 | /***************************************************************** |
2 | * drkonqi - The KDE Crash Handler |
3 | * |
4 | * Copyright (C) 2000-2003 Hans Petter Bieker <bieker@kde.org> |
5 | * Copyright (C) 2009 George Kiagiadakis <gkiagia@users.sourceforge.net> |
6 | * |
7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions |
9 | * are met: |
10 | * |
11 | * 1. Redistributions of source code must retain the above copyright |
12 | * notice, this list of conditions and the following disclaimer. |
13 | * 2. Redistributions in binary form must reproduce the above copyright |
14 | * notice, this list of conditions and the following disclaimer in the |
15 | * documentation and/or other materials provided with the distribution. |
16 | * |
17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | *****************************************************************/ |
28 | #include "backtracegenerator.h" |
29 | |
30 | #include <KDebug> |
31 | #include <KTemporaryFile> |
32 | #include <KShell> |
33 | |
34 | #include "parser/backtraceparser.h" |
35 | |
36 | BacktraceGenerator::BacktraceGenerator(const Debugger & debugger, QObject *parent) |
37 | : QObject(parent), |
38 | m_debugger(debugger), m_proc(NULL), |
39 | m_temp(NULL), m_state(NotLoaded) |
40 | { |
41 | m_parser = BacktraceParser::newParser(m_debugger.codeName(), this); |
42 | m_parser->connectToGenerator(this); |
43 | |
44 | #ifdef BACKTRACE_PARSER_DEBUG |
45 | m_debugParser = BacktraceParser::newParser(QString(), this); //uses the null parser |
46 | m_debugParser->connectToGenerator(this); |
47 | #endif |
48 | } |
49 | |
50 | BacktraceGenerator::~BacktraceGenerator() |
51 | { |
52 | if (m_proc && m_proc->state() == QProcess::Running) { |
53 | kWarning() << "Killing running debugger instance" ; |
54 | m_proc->disconnect(this); |
55 | m_proc->terminate(); |
56 | if (!m_proc->waitForFinished(10000)) { |
57 | m_proc->kill(); |
58 | m_proc->waitForFinished(); |
59 | } |
60 | delete m_proc; |
61 | delete m_temp; |
62 | } |
63 | } |
64 | |
65 | bool BacktraceGenerator::start() |
66 | { |
67 | //they should always be null before entering this function. |
68 | Q_ASSERT(m_proc == NULL && m_temp == NULL); |
69 | |
70 | m_parsedBacktrace.clear(); |
71 | m_state = Loading; |
72 | |
73 | emit starting(); |
74 | |
75 | if (!m_debugger.isValid() || !m_debugger.isInstalled()) { |
76 | m_state = FailedToStart; |
77 | emit failedToStart(); |
78 | return false; |
79 | } |
80 | |
81 | m_proc = new KProcess; |
82 | m_proc->setEnv("LC_ALL" , "C" ); // force C locale |
83 | |
84 | m_temp = new KTemporaryFile; |
85 | m_temp->open(); |
86 | m_temp->write(m_debugger.backtraceBatchCommands().toLatin1()); |
87 | m_temp->write("\n" , 1); |
88 | m_temp->flush(); |
89 | |
90 | // start the debugger |
91 | QString str = m_debugger.command(); |
92 | Debugger::expandString(str, Debugger::ExpansionUsageShell, m_temp->fileName()); |
93 | |
94 | *m_proc << KShell::splitArgs(str); |
95 | m_proc->setOutputChannelMode(KProcess::OnlyStdoutChannel); |
96 | m_proc->setNextOpenMode(QIODevice::ReadWrite | QIODevice::Text); |
97 | connect(m_proc, SIGNAL(readyReadStandardOutput()), |
98 | SLOT(slotReadInput())); |
99 | connect(m_proc, SIGNAL(finished(int,QProcess::ExitStatus)), |
100 | SLOT(slotProcessExited(int,QProcess::ExitStatus))); |
101 | |
102 | m_proc->start(); |
103 | if (!m_proc->waitForStarted()) { |
104 | //we mustn't keep these around... |
105 | m_proc->deleteLater(); |
106 | m_temp->deleteLater(); |
107 | m_proc = NULL; |
108 | m_temp = NULL; |
109 | |
110 | m_state = FailedToStart; |
111 | emit failedToStart(); |
112 | return false; |
113 | } |
114 | |
115 | return true; |
116 | } |
117 | |
118 | void BacktraceGenerator::slotReadInput() |
119 | { |
120 | // we do not know if the output array ends in the middle of an utf-8 sequence |
121 | m_output += m_proc->readAllStandardOutput(); |
122 | |
123 | int pos; |
124 | while ((pos = m_output.indexOf('\n')) != -1) { |
125 | QString line = QString::fromLocal8Bit(m_output, pos + 1); |
126 | m_output.remove(0, pos + 1); |
127 | |
128 | emit newLine(line); |
129 | } |
130 | } |
131 | |
132 | void BacktraceGenerator::slotProcessExited(int exitCode, QProcess::ExitStatus exitStatus) |
133 | { |
134 | //these are useless now |
135 | m_proc->deleteLater(); |
136 | m_temp->deleteLater(); |
137 | m_proc = NULL; |
138 | m_temp = NULL; |
139 | |
140 | //mark the end of the backtrace for the parser |
141 | emit newLine(QString()); |
142 | |
143 | if (exitStatus != QProcess::NormalExit || exitCode != 0) { |
144 | m_state = Failed; |
145 | emit someError(); |
146 | return; |
147 | } |
148 | |
149 | //no translation, string appears in the report |
150 | QString tmp("Application: %progname (%execname), signal: %signame\n" ); |
151 | Debugger::expandString(tmp); |
152 | |
153 | m_parsedBacktrace = tmp + m_parser->parsedBacktrace(); |
154 | m_state = Loaded; |
155 | |
156 | #ifdef BACKTRACE_PARSER_DEBUG |
157 | //append the raw unparsed backtrace |
158 | m_parsedBacktrace += "\n------------ Unparsed Backtrace ------------\n" ; |
159 | m_parsedBacktrace += m_debugParser->parsedBacktrace(); //it's not really parsed, it's from the null parser. |
160 | #endif |
161 | |
162 | emit done(); |
163 | } |
164 | |
165 | #include "backtracegenerator.moc" |
166 | |