--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/core/builtins/ps.cpp Wed Jun 23 15:52:26 2010 +0100
@@ -0,0 +1,548 @@
+// ps.cpp
+//
+// Copyright (c) 2005 - 2010 Accenture. All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Accenture - Initial contribution
+//
+
+#include <fshell/common.mmh>
+#include <fshell/ltkutils.h>
+#include <fshell/heaputils.h>
+#include "ps.h"
+
+_LIT(KDefaultMatch, "*");
+
+CCommandBase* CCmdPs::NewLC()
+ {
+ CCmdPs* self = new(ELeave) CCmdPs();
+ CleanupStack::PushL(self);
+ self->BaseConstructL();
+ return self;
+ }
+
+CCmdPs::~CCmdPs()
+ {
+ delete iMatch;
+ delete iFormatter;
+#ifdef FSHELL_MEMORY_ACCESS_SUPPORT
+ iMemoryAccess.Close();
+#endif
+ }
+
+CCmdPs::CCmdPs()
+ {
+ }
+
+const TDesC& CCmdPs::Name() const
+ {
+ _LIT(KName, "ps");
+ return KName;
+ }
+
+void CCmdPs::DoRunL()
+ {
+ if (iMatch == NULL)
+ {
+ iMatch = KDefaultMatch().AllocL();
+ }
+
+ iFormatter = CTextFormatter::NewL(Stdout());
+
+#ifdef FSHELL_MEMORY_ACCESS_SUPPORT
+ TInt err = RMemoryAccess::LoadDriver();
+ if ((err == KErrNone) || (err == KErrAlreadyExists))
+ {
+ err = iMemoryAccess.Open();
+ }
+ if (err)
+ {
+ PrintWarning(_L("Unable to load memory access device driver: %d"), err);
+ }
+#endif
+
+#if defined(__WINS__) && !defined(EKA2)
+ TFindThread finder(*iMatch);
+ RThread process;
+#else
+ TFindProcess finder(*iMatch);
+ RProcess process;
+#endif
+
+
+ if (iProcessId)
+ {
+ User::LeaveIfError(process.Open(iProcessId));
+ CleanupClosePushL(process);
+ iProcessName = process.Name();
+ PrintInfoL(process);
+ CleanupStack::PopAndDestroy(&process);
+ }
+ else
+ {
+ while (finder.Next(iProcessName) == KErrNone)
+ {
+ TInt err = process.Open(finder);
+ if (err)
+ {
+ PrintWarning(_L("Unable to open handle to process %S: %d"), &iProcessName, err);
+ continue;
+ }
+ if ((iExcludeDead && (process.ExitType() != EExitPending)) || (iOnlyDead && (process.ExitType() == EExitPending)))
+ {
+ process.Close();
+ continue;
+ }
+ CleanupClosePushL(process);
+ PrintInfoL(process);
+ CleanupStack::PopAndDestroy(&process);
+ }
+ }
+
+ Write(iFormatter->Descriptor());
+ Complete();
+ }
+
+void CCmdPs::ArgumentsL(RCommandArgumentList& aArguments)
+ {
+ _LIT(KArg1, "process_id");
+ aArguments.AppendUintL(iProcessId, KArg1);
+ }
+
+void CCmdPs::OptionsL(RCommandOptionList& aOptions)
+ {
+ _LIT(KOptVerbose, "verbose");
+ aOptions.AppendBoolL(iVerbose, KOptVerbose);
+
+ _LIT(KOptMatch, "match");
+ aOptions.AppendStringL(iMatch, KOptMatch);
+
+ _LIT(KOptHuman, "human");
+ aOptions.AppendBoolL(iHuman, KOptHuman);
+
+ _LIT(KOptPriority, "priority");
+ aOptions.AppendBoolL(iPrintPriority, KOptPriority);
+
+ _LIT(KOptExclude, "exclude-dead");
+ aOptions.AppendBoolL(iExcludeDead, KOptExclude);
+
+ _LIT(KOptOnlyDead, "only-dead");
+ aOptions.AppendBoolL(iOnlyDead, KOptOnlyDead);
+
+ _LIT(KOptHandleCount, "handle-count");
+ aOptions.AppendBoolL(iHandleCount, KOptHandleCount);
+
+#if defined(EKA2) || !defined(__WINS__)
+ _LIT(KOptThreads, "threads");
+ aOptions.AppendBoolL(iPrintThreads, KOptThreads);
+
+ _LIT(KOptStack, "stacks");
+ aOptions.AppendBoolL(iPrintStackInfo, KOptStack);
+
+ _LIT(KOptHeap, "heaps");
+ aOptions.AppendBoolL(iPrintHeapInfo, KOptHeap);
+
+ _LIT(KOptCpu, "cpu-time");
+ aOptions.AppendBoolL(iPrintCpuTime, KOptCpu);
+
+ _LIT(KOptChunk, "chunks");
+ aOptions.AppendBoolL(iPrintChunkInfo, KOptChunk);
+
+ _LIT(KOptFileName, "filename");
+ aOptions.AppendBoolL(iPrintFileName, KOptFileName);
+
+ _LIT(KOptMemoryInfo, "memory");
+ aOptions.AppendBoolL(iPrintMemoryInfo, KOptMemoryInfo);
+#endif
+#if !defined(EKA2) && !defined(__WINS__)
+ _LIT(KOptCommandLine, "command_line");
+ aOptions.AppendBoolL(iPrintCommandLine, KOptCommandLine);
+#endif
+#if !defined(EKA2)
+ _LIT(KOptFlags, "flags");
+ aOptions.AppendBoolL(iPrintFlags, KOptFlags);
+#endif
+
+ _LIT(KOptAddresses, "addresses");
+ aOptions.AppendBoolL(iAddresses, KOptAddresses);
+ }
+
+#if defined(__WINS__) && !defined(EKA2)
+void CCmdPs::PrintInfoL(RThread& aProcess)
+#else
+void CCmdPs::PrintInfoL(RProcess& aProcess)
+#endif
+ {
+ TInt processHandleCount = 0;
+
+ TBool dead = aProcess.ExitType() != EExitPending;
+ iFormatter->AppendFormatL(_L("%u "), TUint(aProcess.Id()));
+ if (dead) iFormatter->AppendL(_L("["));
+ if (iVerbose)
+ {
+ iFormatter->AppendL(iProcessName);
+ }
+ else
+ {
+ TFullName name = iProcessName;
+ LtkUtils::MakeProcessNameFriendly(name);
+ iFormatter->AppendL(name);
+ }
+ if (dead) iFormatter->AppendL(_L("]"));
+ iFormatter->AppendL(_L("\r\n"));
+
+ iProcessName.Append(_L("::*"));
+
+ if (iPrintThreads)
+ {
+ iFormatter->AppendL(_L("\tThreads:\r\n"));
+ TFindThread threadFinder(iProcessName);
+ RThread thread;
+ while (threadFinder.Next(iThreadName) == KErrNone)
+ {
+ TInt err = thread.Open(threadFinder);
+ if (err)
+ {
+ if ((err != KErrPermissionDenied) || iVerbose)
+ {
+ PrintWarning(_L("Unable to open handle to thread %S: %d"), &iThreadName, err);
+ }
+ continue;
+ }
+ if ((iExcludeDead && (thread.ExitType() != EExitPending)) || (iOnlyDead && (thread.ExitType() == EExitPending)))
+ {
+ thread.Close();
+ continue;
+ }
+
+ CleanupClosePushL(thread);
+ iThreadName = thread.Name();
+#ifdef EKA2
+ iFormatter->AppendFormatL(_L("\t\t%Lu %S\r\n"), thread.Id().Id(), &iThreadName);
+#else
+ iFormatter->AppendFormatL(_L("\t\t%u %S\r\n"), thread.Id(), &iThreadName);
+#endif
+#ifdef FSHELL_MEMORY_ACCESS_SUPPORT
+ if (iAddresses && iMemoryAccess.Handle())
+ {
+ TObjectKernelInfo objectInfo;
+ TPckg<TObjectKernelInfo> objectInfoPckg(objectInfo);
+ TInt err = iMemoryAccess.GetObjectInfoByHandle(EThread, RThread().Id(), thread.Handle(), objectInfoPckg);
+ if (err == KErrNone)
+ {
+ iFormatter->AppendFormatL(_L("\t\t\tAddress: 0x%08x\r\n"), objectInfo.iAddressOfKernelObject);
+ }
+ }
+#endif // FSHELL_MEMORY_ACCESS_SUPPORT
+ if (iPrintPriority)
+ {
+ iFormatter->AppendFormatL(_L("\t\t\tPriority: %d\r\n"), thread.Priority());
+ }
+ PrintStackInfoL(thread, iThreadName);
+ PrintHeapInfoL(thread, iThreadName);
+ PrintCpuTimeL(thread, iThreadName);
+ if (iHandleCount)
+ {
+ TInt threadHandleCount;
+ thread.HandleCount(processHandleCount, threadHandleCount);
+ iFormatter->AppendFormatL(_L("\t\t\tHandle count: %d\r\n"), threadHandleCount);
+ }
+ CleanupStack::PopAndDestroy(&thread);
+ }
+ }
+ if (iPrintPriority)
+ {
+ iFormatter->AppendFormatL(_L("\tPriority: %d\r\n"), aProcess.Priority());
+ }
+#if defined(EKA2) || !defined(__WINS__)
+ PrintChunkInfoL(iProcessName);
+ if (iPrintFileName)
+ {
+ TFileName fileName(aProcess.FileName());
+ iFormatter->AppendFormatL(_L("\tFile name: %S\r\n"), &fileName);
+ }
+ if (iPrintMemoryInfo)
+ {
+ TProcessMemoryInfo memoryInfo;
+ TInt err = aProcess.GetMemoryInfo(memoryInfo);
+ if (err)
+ {
+ PrintWarning(_L("Couldn't read memory information: %d"), err);
+ }
+ else
+ {
+ iFormatter->AppendFormatL(_L("\tCode base: 0x%08x\r\n"), memoryInfo.iCodeBase);
+ PrintSizeL(_L("\tCode size: "), memoryInfo.iCodeSize);
+ iFormatter->AppendFormatL(_L("\tConst data base: 0x%08x\r\n"), memoryInfo.iConstDataBase);
+ PrintSizeL(_L("\tConst data size: "), memoryInfo.iConstDataSize);
+ iFormatter->AppendFormatL(_L("\tInitialised data base: 0x%08x\r\n"), memoryInfo.iInitialisedDataBase);
+ PrintSizeL(_L("\tInitialised data size: "), memoryInfo.iInitialisedDataSize);
+ iFormatter->AppendFormatL(_L("\tUninitialised data base: 0x%08x\r\n"), memoryInfo.iUninitialisedDataBase);
+ PrintSizeL(_L("\tUninitialised data size: "), memoryInfo.iUninitialisedDataSize);
+ }
+ }
+#endif
+#if !defined(EKA2) && !defined(__WINS__)
+ if (iPrintCommandLine)
+ {
+ HBufC* cl = HBufC::NewL(aProcess.CommandLineLength());
+ TPtr clPtr(cl->Des());
+ aProcess.CommandLine(clPtr);
+ iFormatter->AppendFormatL(_L("\tCommand line: %S\r\n"), cl);
+ delete cl;
+ }
+#endif
+ if (iPrintFlags)
+ {
+#ifndef EKA2
+ iFormatter->AppendFormatL(_L("\tSystem: %d\r\n\tProtected: %d\r\n"), aProcess.System(), aProcess.Protected());
+#endif
+#if !defined(__WINS__) && !defined(EKA2)
+ iFormatter->AppendFormatL(_L("\tLoaded from RAM: %d\r\n"), aProcess.LoadedFromRam());
+#endif
+ }
+
+#ifdef FSHELL_MEMORY_ACCESS_SUPPORT
+ if (iAddresses && iMemoryAccess.Handle())
+ {
+ TObjectKernelInfo objectInfo;
+ TPckg<TObjectKernelInfo> objectInfoPckg(objectInfo);
+ TInt err = iMemoryAccess.GetObjectInfoByHandle(EProcess, RThread().Id(), aProcess.Handle(), objectInfoPckg);
+ if (err == KErrNone)
+ {
+ iFormatter->AppendFormatL(_L("\tAddress: 0x%08x\r\n"), objectInfo.iAddressOfKernelObject);
+ }
+ }
+#endif // FSHELL_MEMORY_ACCESS_SUPPORT
+
+ if (iHandleCount)
+ {
+ if (iPrintThreads)
+ {
+ iFormatter->AppendFormatL(_L("\tProcess handle count: %d\r\n"), processHandleCount);
+ }
+ else
+ {
+ // Summarise the total handle count for this process and all its threads.
+ TInt threadHandleCount = 0;
+ TFindThread threadFinder(iProcessName);
+ RThread thread;
+ while (threadFinder.Next(iThreadName) == KErrNone)
+ {
+ TInt err = thread.Open(threadFinder);
+ if (err)
+ {
+ continue;
+ }
+ TInt thc;
+ thread.HandleCount(processHandleCount, thc);
+ thread.Close();
+ threadHandleCount += thc;
+ }
+ iFormatter->AppendFormatL(_L("\tTotal handle count: %d\r\n"), processHandleCount + threadHandleCount);
+ }
+ }
+ }
+
+void CCmdPs::PrintStackInfoL(RThread& aThread, const TDesC& aThreadName)
+ {
+#ifdef EKA2
+ if (iPrintStackInfo)
+ {
+ TThreadStackInfo stackInfo;
+ TInt err = aThread.StackInfo(stackInfo);
+ if (err)
+ {
+ PrintWarning(_L("Unable to get stack info for thread %S: %d"), &aThreadName, err);
+ }
+ else
+ {
+ const TInt stackSize = stackInfo.iBase - stackInfo.iLimit;
+ iFormatter->AppendFormatL(_L("\t\t\tStack info:\r\n"));
+ PrintSizeL(_L("\t\t\t\tSize: "), stackSize);
+ iFormatter->AppendFormatL(_L("\t\t\t\tBase: 0x%08x\r\n"), stackInfo.iBase);
+ iFormatter->AppendFormatL(_L("\t\t\t\tLimit: 0x%08x\r\n"), stackInfo.iLimit);
+ iFormatter->AppendFormatL(_L("\t\t\t\tExpand limit: 0x%08x\r\n"), stackInfo.iExpandLimit);
+#ifdef FSHELL_MEMORY_ACCESS_SUPPORT
+ if (iMemoryAccess.Handle())
+ {
+ const TInt KBufSize = 4096; // The largest amount RMemoryAccess allows us to copy in one go.
+ HBufC8* stackBuf = HBufC8::NewLC(KBufSize);
+ TPtr8 stackBufPtr(stackBuf->Des());
+ TThreadMemoryAccessParamsBuf accessParamsBuf;
+ TThreadMemoryAccessParams& accessParams = accessParamsBuf();
+ accessParams.iId = (TInt)aThread.Id().Id();
+ TInt numBytesRead = 0;
+ TInt numUnusedBytes = 0;
+ while (numBytesRead < stackSize)
+ {
+ accessParams.iAddr = (TUint8*)stackInfo.iLimit + numBytesRead;
+ accessParams.iSize = Min(KBufSize, stackSize - numBytesRead);
+ stackBufPtr.Zero();
+ err = iMemoryAccess.GetThreadMem(accessParamsBuf, stackBufPtr);
+ if (err)
+ {
+ PrintWarning(_L("Unable to read stack data for thread %S: %d"), &aThreadName, err);
+ break;
+ }
+ else
+ {
+ const TInt bufLength = stackBuf->Length();
+ for (TInt i = 0; i < bufLength; ++i)
+ {
+ if ((*stackBuf)[i] != 0x29)
+ {
+ break;
+ }
+ ++numUnusedBytes;
+ }
+ numBytesRead += bufLength;
+ }
+ }
+ if (err == KErrNone)
+ {
+ const TInt numUsedBytes = stackSize - numUnusedBytes;
+ iFormatter->AppendFormatL(_L("\t\t\t\tHigh water mark: 0x%08x ("), stackInfo.iBase - numUsedBytes);
+ if (iHuman)
+ {
+ iFormatter->AppendHumanReadableSizeL(numUsedBytes, EUnaligned);
+ iFormatter->AppendFormatL(_L(")\r\n"));
+ }
+ else
+ {
+ iFormatter->AppendFormatL(_L("%d bytes)\r\n"), numUsedBytes);
+ }
+ }
+ CleanupStack::PopAndDestroy(stackBuf);
+ }
+#endif // FSHELL_MEMORY_ACCESS_SUPPORT
+ }
+ }
+#endif // EKA2
+ }
+
+#if defined(EKA2) && defined(FSHELL_MEMORY_ACCESS_SUPPORT)
+void CCmdPs::PrintHeapInfoL(RThread& aThread, const TDesC& aThreadName)
+ {
+ if (iPrintHeapInfo && iMemoryAccess.Handle())
+ {
+ LtkUtils::RProxyAllocatorHelper allocHelper;
+ CleanupClosePushL(allocHelper);
+ TInt err = allocHelper.Open(iMemoryAccess, TUint(aThread.Id()));
+ if (err)
+ {
+ PrintWarning(_L("Couldn't open allocator helper for thread %S: %d"), &aThreadName, err);
+ }
+ else
+ {
+ TInt committed = allocHelper.CommittedSize();
+ TInt alloced = allocHelper.AllocatedSize();
+ PrintSizeL(_L("\t\t\tHeap size: "), committed);
+ iFormatter->AppendFormatL(_L("\t\t\tAlloc count: %d\r\n"), allocHelper.AllocationCount());
+ PrintSizeL(_L("\t\t\tAlloc size: "), alloced);
+ }
+ CleanupStack::PopAndDestroy(&allocHelper);
+ }
+ }
+#else
+void CCmdPs::PrintHeapInfoL(RThread&, const TDesC&)
+ {
+ }
+#endif
+
+#ifdef EKA2
+void CCmdPs::PrintCpuTimeL(RThread& aThread, const TDesC& aThreadName)
+ {
+ if (iPrintCpuTime)
+ {
+ TTimeIntervalMicroSeconds time;
+ TInt err = aThread.GetCpuTime(time);
+ if (err)
+ {
+ PrintWarning(_L("Unable to get CPU time for thread %S: %d"), &aThreadName, err);
+ }
+ else
+ {
+ iFormatter->AppendFormatL(_L("\t\t\tCPU time: %Lu\r\n"), time.Int64());
+ }
+ }
+ }
+#else
+void CCmdPs::PrintCpuTimeL(RThread&, const TDesC&)
+ {
+ }
+#endif
+
+void CCmdPs::PrintChunkInfoL(const TDesC& aProcessName)
+ {
+ if (iPrintChunkInfo)
+ {
+ iFormatter->AppendL(_L("\tChunks:\r\n"));
+ TFindChunk findChunk(aProcessName);
+ while (findChunk.Next(iChunkName) == KErrNone)
+ {
+ TPtrC shortChunkName(iChunkName.Mid(aProcessName.Length() - 1));
+ iFormatter->AppendFormatL(_L("\t\t%S\r\n"), &shortChunkName);
+#ifdef EKA2
+#ifdef FSHELL_MEMORY_ACCESS_SUPPORT
+ if (iMemoryAccess.Handle())
+ {
+ TChunkKernelInfo chunkInfo;
+ TPckg<TChunkKernelInfo> chunkInfoPckg(chunkInfo);
+ TInt err = iMemoryAccess.GetObjectInfo(EChunk, iChunkName, chunkInfoPckg);
+ if (err)
+ {
+ PrintWarning(_L("Unable to get info for chunk %S: %d"), &iChunkName, err);
+ }
+ else
+ {
+ iFormatter->AppendFormatL(_L("\t\t\tAddress: 0x%08x\r\n"), chunkInfo.iAddressOfKernelObject);
+ PrintSizeL(_L("\t\t\tSize: "), chunkInfo.iSize);
+ PrintSizeL(_L("\t\t\tMax size: "), chunkInfo.iMaxSize);
+ iFormatter->AppendFormatL(_L("\t\t\tType: %d\r\n"), chunkInfo.iChunkType);
+ }
+ }
+#endif // FSHELL_MEMORY_ACCESS_SUPPORT
+#else // !EKA2
+ RChunk chunk;
+ TInt err = chunk.Open(findChunk);
+ if (err)
+ {
+ PrintWarning(_L("Unable to open chunk %S: %d"), &iChunkName, err);
+ }
+ else
+ {
+ CleanupClosePushL(chunk);
+ PrintSizeL(_L("\t\t\tSize: "), chunk.Size());
+ PrintSizeL(_L("\t\t\tMax size: "), chunk.MaxSize());
+ CleanupStack::PopAndDestroy(&chunk);
+ }
+#endif // EKA2
+ }
+ }
+ }
+
+void CCmdPs::PrintSizeL(const TDesC& aCaption, TInt aSize)
+ {
+ if (iHuman)
+ {
+ iFormatter->AppendL(aCaption);
+ iFormatter->AppendHumanReadableSizeL(aSize, EUnaligned);
+ _LIT(KNewLine, "\r\n");
+ iFormatter->AppendL(KNewLine);
+ }
+ else
+ {
+ _LIT(KFormat, "%S%d\r\n");
+ iFormatter->AppendFormatL(KFormat, &aCaption, aSize);
+ }
+ }
+
+#ifdef EXE_BUILD
+EXE_BOILER_PLATE(CCmdPs)
+#endif
+