blob: 6a0c54c36add8c53e5df20dc3edf7ac141bbc440 [file] [log] [blame]
Stephen Wilsonf6f40332010-07-24 02:19:04 +00001//===-- ProcessLinux.cpp ----------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10// C Includes
Stephen Wilsond1fbbb42011-03-23 02:14:42 +000011#include <errno.h>
12
Stephen Wilsonf6f40332010-07-24 02:19:04 +000013// C++ Includes
14// Other libraries and framework includes
15#include "lldb/Core/PluginManager.h"
Peter Collingbournead115462011-06-03 20:40:44 +000016#include "lldb/Core/State.h"
Stephen Wilsonf6f40332010-07-24 02:19:04 +000017#include "lldb/Host/Host.h"
18#include "lldb/Symbol/ObjectFile.h"
Stephen Wilson92241ef2011-01-16 19:45:39 +000019#include "lldb/Target/DynamicLoader.h"
Stephen Wilsonf6f40332010-07-24 02:19:04 +000020#include "lldb/Target/Target.h"
21
22#include "ProcessLinux.h"
Johnny Chenac51e9f2011-10-11 21:21:57 +000023#include "ProcessLinuxLog.h"
Peter Collingbournead115462011-06-03 20:40:44 +000024#include "Plugins/Process/Utility/InferiorCallPOSIX.h"
Stephen Wilsonf6f40332010-07-24 02:19:04 +000025#include "ProcessMonitor.h"
26#include "LinuxThread.h"
27
28using namespace lldb;
29using namespace lldb_private;
30
31//------------------------------------------------------------------------------
32// Static functions.
33
34Process*
35ProcessLinux::CreateInstance(Target& target, Listener &listener)
36{
37 return new ProcessLinux(target, listener);
38}
39
40void
41ProcessLinux::Initialize()
42{
43 static bool g_initialized = false;
44
45 if (!g_initialized)
46 {
Johnny Chenac51e9f2011-10-11 21:21:57 +000047 g_initialized = true;
Stephen Wilsonf6f40332010-07-24 02:19:04 +000048 PluginManager::RegisterPlugin(GetPluginNameStatic(),
49 GetPluginDescriptionStatic(),
50 CreateInstance);
Johnny Chenac51e9f2011-10-11 21:21:57 +000051
52 Log::Callbacks log_callbacks = {
53 ProcessLinuxLog::DisableLog,
54 ProcessLinuxLog::EnableLog,
55 ProcessLinuxLog::ListLogCategories
56 };
57
58 Log::RegisterLogChannel (ProcessLinux::GetPluginNameStatic(), log_callbacks);
Stephen Wilsonf6f40332010-07-24 02:19:04 +000059 }
60}
61
62void
63ProcessLinux::Terminate()
64{
65}
66
67const char *
68ProcessLinux::GetPluginNameStatic()
69{
70 return "plugin.process.linux";
71}
72
73const char *
74ProcessLinux::GetPluginDescriptionStatic()
75{
76 return "Process plugin for Linux";
77}
78
79
80//------------------------------------------------------------------------------
81// Constructors and destructors.
82
83ProcessLinux::ProcessLinux(Target& target, Listener &listener)
84 : Process(target, listener),
85 m_monitor(NULL),
Stephen Wilson67d9f7e2011-03-30 15:55:52 +000086 m_module(NULL),
87 m_in_limbo(false),
88 m_exit_now(false)
Stephen Wilsonf6f40332010-07-24 02:19:04 +000089{
Greg Claytonce65d2f2011-11-05 01:09:16 +000090
91#if 0
Stephen Wilsonf6f40332010-07-24 02:19:04 +000092 // FIXME: Putting this code in the ctor and saving the byte order in a
93 // member variable is a hack to avoid const qual issues in GetByteOrder.
94 ObjectFile *obj_file = GetTarget().GetExecutableModule()->GetObjectFile();
95 m_byte_order = obj_file->GetByteOrder();
Greg Claytonce65d2f2011-11-05 01:09:16 +000096#else
97 // XXX: Will work only for local processes.
98 m_byte_order = lldb::endian::InlHostByteOrder();
99#endif
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000100}
101
102ProcessLinux::~ProcessLinux()
103{
104 delete m_monitor;
105}
106
107//------------------------------------------------------------------------------
108// Process protocol.
109
110bool
Peter Collingbourne47556982011-07-22 19:12:53 +0000111ProcessLinux::CanDebug(Target &target, bool plugin_specified_by_name)
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000112{
113 // For now we are just making sure the file exists for a given module
114 ModuleSP exe_module_sp(target.GetExecutableModule());
115 if (exe_module_sp.get())
116 return exe_module_sp->GetFileSpec().Exists();
117 return false;
118}
119
120Error
121ProcessLinux::DoAttachToProcessWithID(lldb::pid_t pid)
122{
Johnny Chen9bab8d42011-06-14 19:19:50 +0000123 Error error;
124 assert(m_monitor == NULL);
125
Johnny Chenac51e9f2011-10-11 21:21:57 +0000126 LogSP log (ProcessLinuxLog::GetLogIfAllCategoriesSet (LINUX_LOG_PROCESS));
127 if (log && log->GetMask().Test(LINUX_LOG_VERBOSE))
Johnny Chen3bf3a9d2011-10-18 18:09:30 +0000128 log->Printf ("ProcessLinux::%s(pid = %i)", __FUNCTION__, GetID());
Johnny Chenac51e9f2011-10-11 21:21:57 +0000129
Johnny Chen9bab8d42011-06-14 19:19:50 +0000130 m_monitor = new ProcessMonitor(this, pid, error);
131
132 if (!error.Success())
133 return error;
134
135 SetID(pid);
136 return error;
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000137}
138
139Error
Stephen Wilson92241ef2011-01-16 19:45:39 +0000140ProcessLinux::WillLaunch(Module* module)
141{
142 Error error;
Stephen Wilson92241ef2011-01-16 19:45:39 +0000143 return error;
144}
145
146Error
Greg Claytonce65d2f2011-11-05 01:09:16 +0000147ProcessLinux::DoLaunch (Module *module,
148 const ProcessLaunchInfo &launch_info)
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000149{
150 Error error;
151 assert(m_monitor == NULL);
152
153 SetPrivateState(eStateLaunching);
Greg Claytonce65d2f2011-11-05 01:09:16 +0000154
155 uint32_t launch_flags = launch_info.GetFlags().Get();
156 const char *stdin_path = NULL;
157 const char *stdout_path = NULL;
158 const char *stderr_path = NULL;
159 const char *working_dir = launch_info.GetWorkingDirectory();
160
161 const ProcessLaunchInfo::FileAction *file_action;
162 file_action = launch_info.GetFileActionForFD (STDIN_FILENO);
163 if (file_action)
164 {
165 if (file_action->GetAction () == ProcessLaunchInfo::FileAction::eFileActionOpen)
166 stdin_path = file_action->GetPath();
167 }
168 file_action = launch_info.GetFileActionForFD (STDOUT_FILENO);
169 if (file_action)
170 {
171 if (file_action->GetAction () == ProcessLaunchInfo::FileAction::eFileActionOpen)
172 stdout_path = file_action->GetPath();
173 }
174 file_action = launch_info.GetFileActionForFD (STDERR_FILENO);
175 if (file_action)
176 {
177 if (file_action->GetAction () == ProcessLaunchInfo::FileAction::eFileActionOpen)
178 stderr_path = file_action->GetPath();
179 }
180
181 m_monitor = new ProcessMonitor (this,
182 module,
183 launch_info.GetArguments().GetConstArgumentVector(),
184 launch_info.GetEnvironmentEntries().GetConstArgumentVector(),
185 stdin_path,
186 stdout_path,
187 stderr_path,
188 error);
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000189
190 m_module = module;
191
192 if (!error.Success())
193 return error;
194
Stephen Wilson1f004c62011-01-15 00:13:27 +0000195 SetID(m_monitor->GetPID());
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000196 return error;
197}
198
Stephen Wilson92241ef2011-01-16 19:45:39 +0000199void
200ProcessLinux::DidLaunch()
201{
Stephen Wilson92241ef2011-01-16 19:45:39 +0000202}
203
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000204Error
205ProcessLinux::DoResume()
206{
Stephen Wilson67d9f7e2011-03-30 15:55:52 +0000207 StateType state = GetPrivateState();
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000208
Stephen Wilson67d9f7e2011-03-30 15:55:52 +0000209 assert(state == eStateStopped || state == eStateCrashed);
210
211 // We are about to resume a thread that will cause the process to exit so
212 // set our exit status now. Do not change our state if the inferior
213 // crashed.
214 if (state == eStateStopped)
215 {
216 if (m_in_limbo)
217 SetExitStatus(m_exit_status, NULL);
218 else
219 SetPrivateState(eStateRunning);
220 }
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000221
222 bool did_resume = false;
223 uint32_t thread_count = m_thread_list.GetSize(false);
224 for (uint32_t i = 0; i < thread_count; ++i)
225 {
226 LinuxThread *thread = static_cast<LinuxThread*>(
227 m_thread_list.GetThreadAtIndex(i, false).get());
228 did_resume = thread->Resume() || did_resume;
229 }
230 assert(did_resume && "Process resume failed!");
231
232 return Error();
233}
234
Stephen Wilson01316422011-01-15 00:10:37 +0000235addr_t
236ProcessLinux::GetImageInfoAddress()
237{
238 Target *target = &GetTarget();
239 ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile();
240 Address addr = obj_file->GetImageInfoAddress();
241
242 if (addr.IsValid())
243 return addr.GetLoadAddress(target);
244 else
245 return LLDB_INVALID_ADDRESS;
246}
247
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000248Error
Stephen Wilson3a804312011-01-04 21:41:31 +0000249ProcessLinux::DoHalt(bool &caused_stop)
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000250{
Stephen Wilson67d9f7e2011-03-30 15:55:52 +0000251 Error error;
252
253 if (IsStopped())
254 {
255 caused_stop = false;
256 }
257 else if (kill(GetID(), SIGSTOP))
258 {
259 caused_stop = false;
260 error.SetErrorToErrno();
261 }
262 else
263 {
264 caused_stop = true;
265 }
266
267 return error;
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000268}
269
270Error
271ProcessLinux::DoDetach()
272{
273 return Error(1, eErrorTypeGeneric);
274}
275
276Error
277ProcessLinux::DoSignal(int signal)
278{
Stephen Wilson67d9f7e2011-03-30 15:55:52 +0000279 Error error;
280
281 if (kill(GetID(), signal))
282 error.SetErrorToErrno();
283
284 return error;
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000285}
286
287Error
288ProcessLinux::DoDestroy()
289{
290 Error error;
291
292 if (!HasExited())
293 {
Stephen Wilson67d9f7e2011-03-30 15:55:52 +0000294 // Drive the exit event to completion (do not keep the inferior in
295 // limbo).
296 m_exit_now = true;
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000297
Stephen Wilson67d9f7e2011-03-30 15:55:52 +0000298 if (kill(m_monitor->GetPID(), SIGKILL) && error.Success())
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000299 {
Stephen Wilson67d9f7e2011-03-30 15:55:52 +0000300 error.SetErrorToErrno();
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000301 return error;
302 }
303
Stephen Wilson67d9f7e2011-03-30 15:55:52 +0000304 SetPrivateState(eStateExited);
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000305 }
306
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000307 return error;
308}
309
310void
311ProcessLinux::SendMessage(const ProcessMessage &message)
312{
313 Mutex::Locker lock(m_message_mutex);
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000314
315 switch (message.GetKind())
316 {
317 default:
Stephen Wilson67d9f7e2011-03-30 15:55:52 +0000318 assert(false && "Unexpected process message!");
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000319 break;
320
Stephen Wilson07fc7a92011-01-19 01:29:39 +0000321 case ProcessMessage::eInvalidMessage:
322 return;
323
Stephen Wilson67d9f7e2011-03-30 15:55:52 +0000324 case ProcessMessage::eLimboMessage:
325 m_in_limbo = true;
326 m_exit_status = message.GetExitStatus();
327 if (m_exit_now)
328 {
329 SetPrivateState(eStateExited);
330 m_monitor->Detach();
331 }
332 else
333 SetPrivateState(eStateStopped);
334 break;
335
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000336 case ProcessMessage::eExitMessage:
Stephen Wilson67d9f7e2011-03-30 15:55:52 +0000337 m_exit_status = message.GetExitStatus();
338 SetExitStatus(m_exit_status, NULL);
339 break;
340
341 case ProcessMessage::eTraceMessage:
342 case ProcessMessage::eBreakpointMessage:
343 SetPrivateState(eStateStopped);
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000344 break;
345
346 case ProcessMessage::eSignalMessage:
Stephen Wilson67d9f7e2011-03-30 15:55:52 +0000347 case ProcessMessage::eSignalDeliveredMessage:
348 SetPrivateState(eStateStopped);
349 break;
350
351 case ProcessMessage::eCrashMessage:
352 SetPrivateState(eStateCrashed);
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000353 break;
354 }
Stephen Wilson07fc7a92011-01-19 01:29:39 +0000355
356 m_message_queue.push(message);
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000357}
358
359void
360ProcessLinux::RefreshStateAfterStop()
361{
Johnny Chen3bf3a9d2011-10-18 18:09:30 +0000362 LogSP log (ProcessLinuxLog::GetLogIfAllCategoriesSet (LINUX_LOG_PROCESS));
363 if (log && log->GetMask().Test(LINUX_LOG_VERBOSE))
364 log->Printf ("ProcessLinux::%s()", __FUNCTION__);
365
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000366 Mutex::Locker lock(m_message_mutex);
367 if (m_message_queue.empty())
368 return;
369
370 ProcessMessage &message = m_message_queue.front();
371
Stephen Wilson67d9f7e2011-03-30 15:55:52 +0000372 // Resolve the thread this message corresponds to and pass it along.
Johnny Chen3bf3a9d2011-10-18 18:09:30 +0000373 // FIXME: we're really dealing with the pid here. This should get
374 // fixed when this code is fixed to handle multiple threads.
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000375 lldb::tid_t tid = message.GetTID();
Johnny Chen3bf3a9d2011-10-18 18:09:30 +0000376 if (log)
377 log->Printf ("ProcessLinux::%s() pid = %i", __FUNCTION__, tid);
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000378 LinuxThread *thread = static_cast<LinuxThread*>(
379 GetThreadList().FindThreadByID(tid, false).get());
380
Johnny Chen3bf3a9d2011-10-18 18:09:30 +0000381 assert(thread);
Stephen Wilson67d9f7e2011-03-30 15:55:52 +0000382 thread->Notify(message);
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000383
384 m_message_queue.pop();
385}
386
387bool
388ProcessLinux::IsAlive()
389{
390 StateType state = GetPrivateState();
391 return state != eStateExited && state != eStateInvalid;
392}
393
394size_t
395ProcessLinux::DoReadMemory(addr_t vm_addr,
396 void *buf, size_t size, Error &error)
397{
Johnny Chen3bf3a9d2011-10-18 18:09:30 +0000398 assert(m_monitor);
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000399 return m_monitor->ReadMemory(vm_addr, buf, size, error);
400}
401
402size_t
403ProcessLinux::DoWriteMemory(addr_t vm_addr, const void *buf, size_t size,
404 Error &error)
405{
Johnny Chen3bf3a9d2011-10-18 18:09:30 +0000406 assert(m_monitor);
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000407 return m_monitor->WriteMemory(vm_addr, buf, size, error);
408}
409
410addr_t
411ProcessLinux::DoAllocateMemory(size_t size, uint32_t permissions,
412 Error &error)
413{
Peter Collingbournead115462011-06-03 20:40:44 +0000414 addr_t allocated_addr = LLDB_INVALID_ADDRESS;
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000415
Peter Collingbournead115462011-06-03 20:40:44 +0000416 unsigned prot = 0;
417 if (permissions & lldb::ePermissionsReadable)
418 prot |= eMmapProtRead;
419 if (permissions & lldb::ePermissionsWritable)
420 prot |= eMmapProtWrite;
421 if (permissions & lldb::ePermissionsExecutable)
422 prot |= eMmapProtExec;
423
424 if (InferiorCallMmap(this, allocated_addr, 0, size, prot,
425 eMmapFlagsAnon | eMmapFlagsPrivate, -1, 0)) {
426 m_addr_to_mmap_size[allocated_addr] = size;
427 error.Clear();
428 } else {
429 allocated_addr = LLDB_INVALID_ADDRESS;
430 error.SetErrorStringWithFormat("unable to allocate %zu bytes of memory with permissions %s", size, GetPermissionsAsCString (permissions));
431 }
432
433 return allocated_addr;
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000434}
435
436Error
Peter Collingbournead115462011-06-03 20:40:44 +0000437ProcessLinux::DoDeallocateMemory(lldb::addr_t addr)
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000438{
Peter Collingbournead115462011-06-03 20:40:44 +0000439 Error error;
440 MMapMap::iterator pos = m_addr_to_mmap_size.find(addr);
441 if (pos != m_addr_to_mmap_size.end() &&
442 InferiorCallMunmap(this, addr, pos->second))
443 m_addr_to_mmap_size.erase (pos);
444 else
445 error.SetErrorStringWithFormat("unable to deallocate memory at 0x%llx", addr);
446
447 return error;
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000448}
449
450size_t
451ProcessLinux::GetSoftwareBreakpointTrapOpcode(BreakpointSite* bp_site)
452{
453 static const uint8_t g_i386_opcode[] = { 0xCC };
454
455 ArchSpec arch = GetTarget().GetArchitecture();
456 const uint8_t *opcode = NULL;
457 size_t opcode_size = 0;
458
Stephen Wilsona1f0b722011-02-24 19:17:09 +0000459 switch (arch.GetCore())
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000460 {
461 default:
462 assert(false && "CPU type not supported!");
463 break;
464
Stephen Wilsona1f0b722011-02-24 19:17:09 +0000465 case ArchSpec::eCore_x86_32_i386:
466 case ArchSpec::eCore_x86_64_x86_64:
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000467 opcode = g_i386_opcode;
468 opcode_size = sizeof(g_i386_opcode);
469 break;
470 }
471
472 bp_site->SetTrapOpcode(opcode, opcode_size);
473 return opcode_size;
474}
475
476Error
477ProcessLinux::EnableBreakpoint(BreakpointSite *bp_site)
478{
479 return EnableSoftwareBreakpoint(bp_site);
480}
481
482Error
483ProcessLinux::DisableBreakpoint(BreakpointSite *bp_site)
484{
485 return DisableSoftwareBreakpoint(bp_site);
486}
487
488uint32_t
489ProcessLinux::UpdateThreadListIfNeeded()
490{
491 // Do not allow recursive updates.
492 return m_thread_list.GetSize(false);
493}
494
Johnny Chenb8f74aa2011-10-10 23:11:50 +0000495uint32_t
496ProcessLinux::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list)
497{
Johnny Chenac51e9f2011-10-11 21:21:57 +0000498 LogSP log (ProcessLinuxLog::GetLogIfAllCategoriesSet (LINUX_LOG_THREAD));
499 if (log && log->GetMask().Test(LINUX_LOG_VERBOSE))
Johnny Chen3bf3a9d2011-10-18 18:09:30 +0000500 log->Printf ("ProcessLinux::%s() (pid = %i)", __FUNCTION__, GetID());
Johnny Chenac51e9f2011-10-11 21:21:57 +0000501
Johnny Chen3bf3a9d2011-10-18 18:09:30 +0000502 // Update the process thread list with this new thread.
503 // FIXME: We should be using tid, not pid.
504 assert(m_monitor);
505 ThreadSP thread_sp (old_thread_list.FindThreadByID (GetID(), false));
506 if (!thread_sp)
507 thread_sp.reset(new LinuxThread(*this, GetID()));
508
509 if (log && log->GetMask().Test(LINUX_LOG_VERBOSE))
510 log->Printf ("ProcessLinux::%s() updated pid = %i", __FUNCTION__, GetID());
511 new_thread_list.AddThread(thread_sp);
512
513 return new_thread_list.GetSize(false);
Johnny Chenb8f74aa2011-10-10 23:11:50 +0000514}
515
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000516ByteOrder
517ProcessLinux::GetByteOrder() const
518{
519 // FIXME: We should be able to extract this value directly. See comment in
520 // ProcessLinux().
521 return m_byte_order;
522}
523
Stephen Wilsond1fbbb42011-03-23 02:14:42 +0000524size_t
525ProcessLinux::PutSTDIN(const char *buf, size_t len, Error &error)
526{
527 ssize_t status;
528 if ((status = write(m_monitor->GetTerminalFD(), buf, len)) < 0)
529 {
530 error.SetErrorToErrno();
531 return 0;
532 }
533 return status;
534}
535
536size_t
537ProcessLinux::GetSTDOUT(char *buf, size_t len, Error &error)
538{
539 ssize_t bytes_read;
540
541 // The terminal file descriptor is always in non-block mode.
542 if ((bytes_read = read(m_monitor->GetTerminalFD(), buf, len)) < 0)
543 {
544 if (errno != EAGAIN)
545 error.SetErrorToErrno();
546 return 0;
547 }
548 return bytes_read;
549}
550
551size_t
552ProcessLinux::GetSTDERR(char *buf, size_t len, Error &error)
553{
554 return GetSTDOUT(buf, len, error);
555}
556
Stephen Wilson67d9f7e2011-03-30 15:55:52 +0000557UnixSignals &
558ProcessLinux::GetUnixSignals()
559{
560 return m_linux_signals;
561}
Stephen Wilsond1fbbb42011-03-23 02:14:42 +0000562
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000563//------------------------------------------------------------------------------
564// ProcessInterface protocol.
565
566const char *
567ProcessLinux::GetPluginName()
568{
569 return "process.linux";
570}
571
572const char *
573ProcessLinux::GetShortPluginName()
574{
575 return "process.linux";
576}
577
578uint32_t
579ProcessLinux::GetPluginVersion()
580{
581 return 1;
582}
583
584void
585ProcessLinux::GetPluginCommandHelp(const char *command, Stream *strm)
586{
587}
588
589Error
590ProcessLinux::ExecutePluginCommand(Args &command, Stream *strm)
591{
592 return Error(1, eErrorTypeGeneric);
593}
594
595Log *
596ProcessLinux::EnablePluginLogging(Stream *strm, Args &command)
597{
598 return NULL;
599}
600
601//------------------------------------------------------------------------------
602// Utility functions.
603
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000604bool
605ProcessLinux::HasExited()
606{
607 switch (GetPrivateState())
608 {
609 default:
610 break;
611
Stephen Wilsonf6f40332010-07-24 02:19:04 +0000612 case eStateDetached:
613 case eStateExited:
614 return true;
615 }
616
617 return false;
618}
Stephen Wilson67d9f7e2011-03-30 15:55:52 +0000619
620bool
621ProcessLinux::IsStopped()
622{
623 switch (GetPrivateState())
624 {
625 default:
626 break;
627
628 case eStateStopped:
629 case eStateCrashed:
630 case eStateSuspended:
631 return true;
632 }
633
634 return false;
635}