2 KSysGuard, the KDE System Guard
4 Copyright (C) 2007 Trent Waddington <trent.waddington@gmail.com>
5 Copyright (c) 2008 John Tapsell <tapsell@kde.org>
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
17 You should have received a copy of the GNU Library General Public License
18 aint with this library; see the file COPYING.LIB. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA.
25 #include "../config-ksysguard.h"
34 #ifdef HAVE_SYS_PTRACE_H
35 #include <sys/ptrace.h>
37 #include <sys/types.h>
39 #include <sys/syscall.h>
44 #define REG_ORIG_ACCUM(regs) regs.orig_eax
45 #define REG_ACCUM(regs) regs.eax
46 #define REG_PARAM1(regs) regs.ebx
47 #define REG_PARAM2(regs) regs.ecx
48 #define REG_PARAM3(regs) regs.edx
51 #define REG_ORIG_ACCUM(regs) regs.orig_rax
52 #define REG_ACCUM(regs) regs.rax
53 #define REG_PARAM1(regs) regs.rdi
54 #define REG_PARAM2(regs) regs.rsi
55 #define REG_PARAM3(regs) regs.rdx
57 #if defined(__ppc__) || defined(__powerpc__) || defined(__powerpc64__) || defined(__PPC__) || defined(powerpc)
58 #define REG_ORIG_ACCUM(regs) regs.gpr[0]
59 #define REG_ACCUM(regs) regs.gpr[3]
60 #define REG_PARAM1(regs) regs.orig_gpr3
61 #define REG_PARAM2(regs) regs.gpr[4]
62 #define REG_PARAM3(regs) regs.gpr[5]
70 #define REG_ORIG_ACCUM(regs) regs.pt.gr[15]
71 #define REG_ACCUM(regs) (regs.pt.gr[10] ? -regs.pt.gr[8] : regs.pt.gr[8])
72 #define REG_PARAM1(regs) regs.arg[0]
73 #define REG_PARAM2(regs) regs.arg[1]
74 #define REG_PARAM3(regs) regs.arg[2]
77 #include "KMonitorProcessIO.h"
79 #include "KMonitorProcessIO.moc"
81 KMonitorProcessIO::KMonitorProcessIO(QWidget
* parent
, int pid
)
82 : KTextEditVT( parent
), mPid(pid
)
84 mIncludeChildProcesses
= true;
85 remove_duplicates
= false;
88 mTimer
.setSingleShot(false);
89 connect(&mTimer
, SIGNAL(timeout()), this, SLOT(update()));
91 lastdir
= 3; //an invalid direction, so that the color gets set the first time
94 setParseAnsiEscapeCodes(true);
95 document()->setMaximumBlockCount(100);
96 mCursor
= textCursor();
104 KMonitorProcessIO::~KMonitorProcessIO() {
108 int KMonitorProcessIO::updateInterval() const {
109 return mUpdateInterval
;
112 void KMonitorProcessIO::setUpdateInterval(int msecs
) {
113 mUpdateInterval
= msecs
;
114 if(mTimer
.isActive()) {
116 mTimer
.start(msecs
); //Start with the new interval time
121 void KMonitorProcessIO::detach() {
122 foreach(int pid
, attached_pids
) {
127 int KMonitorProcessIO::attachedPid() const {
130 void KMonitorProcessIO::detach(int pid
) {
132 #ifdef HAVE_SYS_PTRACE_H
133 if(!ptrace(PTRACE_DETACH
, pid
, 0, 0)) {
134 //successfully detached
135 } else if(kill(pid
, 0) < 0) {
137 kDebug() << "Something seriously strange when trying to detach.";
138 } else if (kill(pid
, SIGSTOP
) < 0) {
140 kDebug() << "Something seriously strange when trying to detach and then trying to stop the process";
143 if (waitpid(pid
, &status
, 0) < 0) {
145 kDebug() << "Something seriously strange when trying to detach and waiting for process to stop";
148 if (!WIFSTOPPED(status
)) {
149 /* Au revoir, mon ami. */
152 if (WSTOPSIG(status
) == SIGSTOP
) {
153 //Okay process is now stopped. Lets try detaching again. Silly linux.
154 if (ptrace(PTRACE_DETACH
,pid
, 0, 0) < 0) {
156 kDebug() << "Something seriously strange when trying to detach the second time.";
161 // we didn't manage to stop the process. Lets try continuing it and the stopping it
162 if (ptrace(PTRACE_CONT
, pid
, 0, 0) < 0) {
164 kDebug() << "Something seriously strange when trying to detach and continue";
170 attached_pids
.removeAll(pid
);
172 if(attached_pids
.isEmpty()) {
177 bool KMonitorProcessIO::reattach() {
183 bool KMonitorProcessIO::attach(int pid
) {
185 //Indicates to detach all
189 #ifdef HAVE_SYS_PTRACE_H
190 if (ptrace(PTRACE_ATTACH
, pid
, 0, 0) == -1) {
191 kDebug() << "Failed to attach to process " << pid
;
192 if(attached_pids
.isEmpty()) {
194 insertHtml(i18n("<br/><i><font color=\"gray\">Failed to attach to process %1</font></i><br/>", pid
));
198 if(attached_pids
.isEmpty()) {
199 //First process added. Automatically start timer
200 ptrace(PTRACE_SYSCALL
, pid
, 0, 0);
201 mTimer
.start(mUpdateInterval
);
205 attached_pids
.append(pid
);
213 void KMonitorProcessIO::update(bool modified
)
215 #ifdef HAVE_SYS_PTRACE_H
216 static QColor writeColor
= QColor(255,0,0);
217 static QColor readColor
= QColor(0,0,255);
220 int pid
= waitpid(-1, &status
, WNOHANG
| WUNTRACED
| WCONTINUED
);
221 if (pid
== -1 || !WIFSTOPPED(status
)) {
223 ensureCursorVisible();
226 #if defined(__ppc__) || defined(__powerpc__) || defined(__powerpc64__) || defined(__PPC__) || defined(powerpc)
228 regs
.gpr
[0] = ptrace(PTRACE_PEEKUSER
, pid
, 4 * PT_R0
, 0);
229 regs
.gpr
[3] = ptrace(PTRACE_PEEKUSER
, pid
, 4 * PT_R3
, 0);
230 regs
.gpr
[4] = ptrace(PTRACE_PEEKUSER
, pid
, 4 * PT_R4
, 0);
231 regs
.gpr
[5] = ptrace(PTRACE_PEEKUSER
, pid
, 4 * PT_R5
, 0);
232 regs
.orig_gpr3
= ptrace(PTRACE_PEEKUSER
, pid
, 4 * PT_ORIG_R3
, 0);
236 struct pt_all_user_regs pt
;
237 unsigned long arg
[3];
239 ptrace(PTRACE_GETREGS
, pid
, 0, ®s
.pt
);
240 if (REG_ORIG_ACCUM(regs
) >= 0) {
241 unsigned long *out0
= ia64_rse_skip_regs((unsigned long *)regs
.pt
.ar
[17], -(regs
.pt
.cfm
& 0x7f) + ((regs
.pt
.cfm
>> 7) & 0x7f));
242 regs
.arg
[0] = ptrace(PTRACE_PEEKDATA
, pid
, ia64_rse_skip_regs(out0
, 0), 0);
243 regs
.arg
[1] = ptrace(PTRACE_PEEKDATA
, pid
, ia64_rse_skip_regs(out0
, 1), 0);
244 regs
.arg
[2] = ptrace(PTRACE_PEEKDATA
, pid
, ia64_rse_skip_regs(out0
, 2), 0);
247 #if defined __i386__ || defined __amd64__
248 struct user_regs_struct regs
;
249 ptrace(PTRACE_GETREGS
, pid
, 0, ®s
);
251 /*unsigned int b = ptrace(PTRACE_PEEKTEXT, pid, regs.eip, 0);*/
252 if (mIncludeChildProcesses
&& (
254 REG_ORIG_ACCUM(regs
) == SYS_fork
||
257 REG_ORIG_ACCUM(regs
) == SYS_clone
||
260 REG_ORIG_ACCUM(regs
) == SYS_clone2
||
263 if (REG_ACCUM(regs
) > 0)
264 attach(REG_ACCUM(regs
));
266 if ((REG_ORIG_ACCUM(regs
) == SYS_read
|| REG_ORIG_ACCUM(regs
) == SYS_write
) && (REG_PARAM3(regs
) == REG_ACCUM(regs
))) {
267 for (unsigned long i
= 0; i
< REG_PARAM3(regs
); i
++) {
270 unsigned char c
[sizeof(long)];
272 a
.l
= ptrace(PTRACE_PEEKDATA
, pid
, REG_PARAM2(regs
) + i
, 0);
274 //Before we add text or change the color, make sure we are at the end
275 moveCursor(QTextCursor::End
);
277 if(REG_ORIG_ACCUM(regs
) != lastdir
) {
278 if(REG_ORIG_ACCUM(regs
) == SYS_read
)
279 setTextColor(readColor
);
281 setTextColor(writeColor
);
282 lastdir
= REG_ORIG_ACCUM(regs
);
284 for (unsigned j
= 0; j
< sizeof(a
.c
) && i
< REG_PARAM3(regs
); i
++, j
++) {
285 unsigned char c
= a
.c
[j
];
286 /** Use the KTextEditVT specific function to parse the character 'c' */
287 insertVTChar(QChar(c
));
292 ptrace(PTRACE_SYSCALL
, pid
, 0, 0);
297 void KMonitorProcessIO::setIncludeChildProcesses(bool include
) {
298 mIncludeChildProcesses
= include
;
301 bool KMonitorProcessIO::includeChildProcesses() const {
302 return mIncludeChildProcesses
;
306 KMonitorProcessIO::State
KMonitorProcessIO::state() const {
307 if(attached_pids
.isEmpty())
309 if(mTimer
.isActive())
310 return AttachedRunning
;
311 return AttachedPaused
;
314 void KMonitorProcessIO::pauseProcesses() {
315 if(state() == AttachedRunning
) {
319 void KMonitorProcessIO::resumeProcesses() {
320 if(state() == AttachedPaused
)
321 mTimer
.start(mUpdateInterval
);
324 void KMonitorProcessIO::setState(State new_state
) {
325 if(new_state
== AttachedPaused
) pauseProcesses();
326 if(new_state
== AttachedRunning
) resumeProcesses();
327 if(new_state
== Detached
) detach();