1) Fix for Bug 3027 - [GCCE] Unintended operator precedence in ambiguous expressions
2) Fix for Bug 3034 - [GCCE] FLASH_BUS macros are ambiguous w.r.t operator precedence
// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "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:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// e32\kernel\kdebug.cpp
//
//
#include <kernel/kdebug.h>
#include <kernel/kernel.h>
#include "memmodel.h"
#include "debug.h"
#include <kernel/cache.h>
#include "kdebug_priv.h"
/**
Stop-mode debugger offset tables
This tables give the stop-mode debugger a description of the important
kernel objects. Enumeration for each entry is given in debug.h
*/
const TInt Debugger::ObjectOffsetTable[]=
{
// DDebuggerInfo info
_FOFF(DDebuggerInfo, iObjectOffsetTable),
_FOFF(DDebuggerInfo, iObjectOffsetTableCount),
_FOFF(DDebuggerInfo, iThreadContextTable),
_FOFF(DDebuggerInfo, iVersion),
_FOFF(DDebuggerInfo, iOSVersion),
KDebuggerOffsetInvalid,
_FOFF(DDebuggerInfo, iContainers),
_FOFF(DDebuggerInfo, iScheduler),
_FOFF(DDebuggerInfo, iCurrentThread),
_FOFF(DDebuggerInfo, iCodeSegGlobalList),
_FOFF(DDebuggerInfo, iCodeSegLock),
_FOFF(DDebuggerInfo, iChange),
// DMutex info
_FOFF(DMutex, iHoldCount),
// more DDebuggerInfo info
_FOFF(DDebuggerInfo, iShadowPages),
_FOFF(DDebuggerInfo, iShadowPageCount),
_FOFF(DDebuggerInfo, iEventMask),
// DObjectCon info
_FOFF(DObjectCon, iMutex),
_FOFF(DObjectCon, iObjects),
_FOFF(DObjectCon, iCount),
// more DDebuggerInfo info
_FOFF(DDebuggerInfo, iEventHandlerBreakpoint),
_FOFF(DDebuggerInfo, iMemoryModelType),
_FOFF(DDebuggerInfo, iMemModelObjectOffsetTable),
_FOFF(DDebuggerInfo, iMemModelObjectOffsetTableCount),
// thread info
_FOFF(DThread, iName),
_FOFF(DThread, iId),
_FOFF(DThread, iOwningProcess),
_FOFF(DThread, iNThread),
_FOFF(DThread, iSupervisorStack),
_FOFF(DThread, iSupervisorStackSize),
_FOFF(DThread, iUserStackRunAddress),
_FOFF(DThread, iUserStackSize),
_FOFF(DThread, iNThread.iSpare3 /*iUserContextType*/),
_FOFF(DThread, iNThread.iSavedSP),
_FOFF(DThread, iNThread.iPriority),
_FOFF(DThread, iThreadType),
KDebuggerOffsetInvalid,
// process info
_FOFF(DProcess, iName),
_FOFF(DProcess, iId),
_FOFF(DProcess, iAttributes),
_FOFF(DProcess, iCodeSeg),
_FOFF(DProcess, iDataBssRunAddress),
_FOFF(DProcess, iDataBssStackChunk),
#ifdef __MEMMODEL_MOVING__
_FOFF(DMemModelProcess, iNumChunks), //ARMv5 specific
_FOFF(DMemModelProcess, iChunks), //ARMv5 specific
#else
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid,
#endif
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid,
// chunkinfo info
#ifdef __MEMMODEL_MOVING__
_FOFF(DMemModelProcess::SChunkInfo, iDataSectionBase), //ARMv5 specific
_FOFF(DMemModelProcess::SChunkInfo, iChunk), //ARMv5 specific
#else
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid,
#endif
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid,
// chunk info
#ifdef __MEMMODEL_MOVING__
_FOFF(DMemModelChunk, iOwningProcess), //ARMv5 specific
#else
KDebuggerOffsetInvalid,
#endif
_FOFF(DMemModelChunk, iSize),
_FOFF(DMemModelChunk, iAttributes),
_FOFF(DMemModelChunk, iChunkType),
#ifdef __MEMMODEL_MOVING__
_FOFF(DMemModelChunk, iChunkState), //ARMv5 specific
_FOFF(DMemModelChunk, iHomeBase), //ARMv5 specific
#else
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid,
#endif
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid,
// library info
_FOFF(DLibrary, iMapCount),
_FOFF(DLibrary, iState),
_FOFF(DLibrary, iCodeSeg),
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid,
// code seg info
_FOFF(DCodeSeg, iLink.iNext),
_FOFF(DCodeSeg, iLink.iPrev),
_FOFF(DCodeSeg, iDeps),
_FOFF(DCodeSeg, iDepCount),
_FOFF(DCodeSeg, iFileName),
_FOFF(DEpocCodeSeg, iXIP),
_FOFF(DEpocCodeSeg, iInfo),
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid,
// scheduler info
_FOFF(TScheduler, iKernCSLocked),
_FOFF(TScheduler, iLock.iWaiting),
_FOFF(TScheduler, iCurrentThread),
_FOFF(TScheduler, iAddressSpace),
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid,
// code segment information non-XIP
_FOFF(SRamCodeInfo, iCodeSize),
_FOFF(SRamCodeInfo, iTextSize),
_FOFF(SRamCodeInfo, iDataSize),
_FOFF(SRamCodeInfo, iBssSize),
_FOFF(SRamCodeInfo, iCodeRunAddr),
_FOFF(SRamCodeInfo, iCodeLoadAddr),
_FOFF(SRamCodeInfo, iDataRunAddr),
_FOFF(SRamCodeInfo, iDataLoadAddr),
_FOFF(SRamCodeInfo, iConstOffset),
_FOFF(SRamCodeInfo, iExportDir),
_FOFF(SRamCodeInfo, iExportDirCount),
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid,
// code segment information XIP
_FOFF(TRomImageHeader, iCodeAddress),
_FOFF(TRomImageHeader, iDataAddress),
_FOFF(TRomImageHeader, iDataBssLinearBase),
_FOFF(TRomImageHeader, iCodeSize),
_FOFF(TRomImageHeader, iTextSize),
_FOFF(TRomImageHeader, iDataSize),
_FOFF(TRomImageHeader, iBssSize),
_FOFF(TRomImageHeader, iExportDir),
_FOFF(TRomImageHeader, iExportDirCount),
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid,
_FOFF(DDebuggerInfo, iStopModeExtension),
_FOFF(Debug::DStopModeExtension, iFunctionalityBlock),
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid,
// Event filtering information
_FOFF(DDebuggerInfo, iFilterBuffer),
_FOFF(DDebuggerInfo, iFilterBufferSize),
_FOFF(DDebuggerInfo, iFilterBufferInUse),
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid,
// more thread info
_FOFF(DThread, iExitType),
_FOFF(DThread, iExitCategory),
_FOFF(DThread, iExitReason),
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid
};
#ifdef __MEMMODEL_MOVING__
const TInt Debugger::VariantObjectOffsetTable[]=
{
_FOFF(DMemModelProcess, iNumChunks),
_FOFF(DMemModelProcess, iChunks),
_FOFF(DMemModelProcess::SChunkInfo, iDataSectionBase),
_FOFF(DMemModelProcess::SChunkInfo, iChunk),
_FOFF(DMemModelChunk, iOwningProcess),
_FOFF(DMemModelChunk, iChunkState),
_FOFF(DMemModelChunk, iHomeBase),
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid
};
#elif __MEMMODEL_MULTIPLE__
const TInt Debugger::VariantObjectOffsetTable[]=
{
_FOFF(DMemModelProcess, iOsAsid),
_FOFF(DMemModelProcess, iLocalPageDir),
_FOFF(DMemModelProcess, iChunkCount),
_FOFF(DMemModelProcess, iChunks),
_FOFF(DMemModelProcess::SChunkInfo, iChunk),
_FOFF(DMemModelChunk, iOwningProcess),
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid
};
#elif __MEMMODEL_FLEXIBLE__
const TInt Debugger::VariantObjectOffsetTable[]=
{
_FOFF(DMemModelProcess, iOsAsid),
_FOFF(DMemModelProcess, iPageDir),
_FOFF(DMemModelProcess, iChunkCount),
_FOFF(DMemModelProcess, iChunks),
_FOFF(DMemModelProcess::SChunkInfo, iChunk),
_FOFF(DMemModelChunk, iOwningProcess),
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid,
KDebuggerOffsetInvalid
};
#else
//Debug API is not supported for other memory models apart from moving & multiple
__ASSERT_COMPILE(EFalse);
#endif
//
// Reschedule hook to enable thread context type
//
DDebuggerInfo* TheDebuggerInfo = NULL;
inline NThread*& CurrentThread() { return TheDebuggerInfo->iCurrentThread; }
inline volatile TUint32& Change() { return TheDebuggerInfo->iChange; }
void RescheduleCallback(NThread* aNThread)
/**
Main scheduler callback.
Called with the Kernel Lock (Preemption Lock) held.
*/
{
// The 'CurrentThread' is now unscheduled and has become the 'previous thread'
// Set this thread 'UserContextType'...
CurrentThread()->SetUserContextType();
// Make the newly scheduled thread the CurrentThread
CurrentThread() = aNThread;
}
void RescheduleCallbackFirst(NThread* aNThread)
/**
Scheduler callback used once for initialisation.
Called with the Kernel Lock (Preemption Lock) held.
*/
{
// Initialise CurrentThread
CurrentThread() = aNThread;
// Switch future callbacks to the main RescheduleCallback
NKern::SetRescheduleCallback(RescheduleCallback);
}
void EnableRescheduleCallback()
/**
Sets the Scheduler to call us back on every thread reschedule
*/
{
// Reset the User Context Type for all threads, because these values
// will be out-of-date. (It is our Rescheduler callback which set's them.
// and we're just about enable that.)
NKern::ThreadEnterCS(); // Prevent us from dying or suspending whilst holding a DMutex
DObjectCon& threads = *Kern::Containers()[EThread]; // Get container holding threads
threads.Wait(); // Obtain the container mutex so the list does get changed under us
// For each thread...
TInt count = threads.Count();
for (TInt i = 0; i < count; ++i)
{
((DThread*)threads[i])->iNThread.ResetUserContextType();
}
threads.Signal(); // Release the container mutex
NKern::ThreadLeaveCS(); // End of critical section
// Ask for callback
NKern::Lock();
NKern::SetRescheduleCallback(RescheduleCallbackFirst);
NKern::Unlock();
}
void DisableRescheduleCallback()
/**
Stops the Scheduler calling us on every context switch
*/
{
// Prevent rescheduling whilst we disable the callback
NKern::Lock();
// Disable Callback
NKern::SetRescheduleCallback(NULL);
// Invalidate CurrentThread
CurrentThread() = NULL;
// Callback now disabled...
NKern::Unlock();
}
void RemoveSchedulerHooks()
/**
Removes the patches added to the Scheduler code.
*/
{
// Make sure callback is disabled (required before removing hooks)
DisableRescheduleCallback();
// Get range of memory used by hooks
TLinAddr start, end;
NKern::SchedulerHooks(start, end);
// Free shadow pages which cover hooks
TUint32 pageSize=Kern::RoundToPageSize(1);
// Enter CS as we're handling shadowing
NKern::ThreadEnterCS();
// Free all shadow pages, a page at a time
for (TLinAddr addr = start; addr < end; addr += pageSize)
{
Epoc::FreeShadowPage(addr); // Ignore errors because we're trying to clean up anyway
}
// And release
NKern::ThreadLeaveCS();
}
TInt InsertSchedulerHooks()
/**
Enables use of the Scheduler callback by using shadow pages to patch the Scheduler code.
*/
{
// Get range of memory used by hooks
TLinAddr start, end;
NKern::Lock();
NKern::SchedulerHooks(start, end);
NKern::Unlock();
// Create shadow pages for hooks
TUint32 pageSize = Kern::RoundToPageSize(1);
for (TLinAddr addr = start; addr < end; addr += pageSize)
{
// Enter CS whilst handling shadowing
NKern::ThreadEnterCS();
// Allocate the shadow page
TInt r = Epoc::AllocShadowPage(addr);
// And leave...
NKern::ThreadLeaveCS();
// Check for unrecoverable errors
if (r != KErrNone && r != KErrAlreadyExists)
{
// Bail out
NKern::Lock();
RemoveSchedulerHooks();
NKern::Unlock();
return r;
}
}
// Put hooks in
NKern::Lock();
NKern::InsertSchedulerHooks();
NKern::Unlock();
// Make I and D caches consistant for hook region
Cache::IMB_Range(start, (end - start));
return KErrNone;
}
//
// Event handler for change notification
//
DEventHandler::DEventHandler()
: DKernelEventHandler(EventHandler, this)
{
}
DEventHandler* DEventHandler::New()
{
__KTRACE_OPT(KBOOT, Kern::Printf(">>DEventHandler::New"));
// Create new object
DEventHandler* handler = new DEventHandler();
if (handler)
{
// Get sizes required for event handler fn.
const TUint32 KPagesNotMapped = ~0u;
TUint32 physAddr = KPagesNotMapped;
const TUint handlerSize = DummyHandlerSize();
// Allocate some RAM to copy the fn. into
TInt err = Epoc::AllocPhysicalRam(handlerSize, physAddr);
if (!err)
{
// Set up an executable HW chunk for the fn.
err = DPlatChunkHw::New(handler->iHwChunk, physAddr, handlerSize, EMapAttrSupRwx | EMapAttrFullyBlocking);
}
if (!err)
{
const TLinAddr linAddr = handler->iHwChunk->iLinAddr;
CopyDummyHandler(linAddr);
// NB: flushing not required since chunk is uncacheable
// Cache::IMBRange(linAddr, handlerSize);
}
if (err)
{
__KTRACE_OPT(KBOOT, Kern::Printf("DEventHandler::New() failing with err = %d", err));
// Free handler (and hence chunk), if any
delete handler;
handler = NULL;
// Free RAM, if allocated
if (physAddr != KPagesNotMapped)
{
Epoc::FreePhysicalRam(physAddr, handlerSize);
}
}
}
__KTRACE_OPT(KBOOT, Kern::Printf("<<DEventHandler::New, returning 0x%08x", handler));
return handler;
}
void DEventHandler::CopyDummyHandler(TLinAddr aLinAddr)
{
const TUint handlerSize = DummyHandlerSize();
// Copy the breakpoint-able handler into RAM by copying from the one (possibly) in ROM
memcpy((TAny*)aLinAddr, (TAny*) &DummyHandler, handlerSize);
__KTRACE_OPT(KBOOT, Kern::Printf("Breakpoint-able handler copied from 0x%x to (va) 0x%x, size %d", &DummyHandler, aLinAddr, handlerSize));
}
DEventHandler::~DEventHandler()
{
if (iHwChunk)
{
const TPhysAddr physAddr = iHwChunk->iPhysAddr;
const TInt size = iHwChunk->iSize;
iHwChunk->Close(NULL);
Epoc::FreePhysicalRam(physAddr, size);
}
}
TInt DEventHandler::Add(TAddPolicy aPolicy)
{
__KTRACE_OPT(KBOOT, Kern::Printf("DEventHandler::Add"));
// Check we have a debug info table to add the handler into
if (!TheDebuggerInfo)
{
__KTRACE_OPT(KBOOT, Kern::Printf("No DDebuggerInfo created yet - cannot add breakpointable handler!"));
return KErrNotReady;
}
// Install the breakpoint-able handler
TheDebuggerInfo->iEventHandlerBreakpoint = iHwChunk->iLinAddr;
// Add the handler to the queue
return DKernelEventHandler::Add(aPolicy);
}
/**
Event handler that monitors changes for processes, threads, chunks, libraries and code segments
Changes are flagged in the iChange member of DDebuggerInfo
*/
TUint DEventHandler::EventHandler(TKernelEvent aType, TAny* a1, TAny* a2, TAny* aThis)
{
TUint ret = DKernelEventHandler::ERunNext;
TheDebuggerInfo->LockFilterBuffer();
TFilterHeader* hdr = (TFilterHeader*)TheDebuggerInfo->iFilterBuffer;
TBool interested = EFalse;
TBool hdrPresent = hdr && (hdr->iSignature == KFilterBufferSignature);
// Update the appropriate bit in the change bitmask
switch (aType)
{
case EEventAddCodeSeg:
case EEventRemoveCodeSeg:
{
DCodeSeg* codeSeg = (DCodeSeg*)a1;
interested = hdrPresent && DEventHandler::InterestedIn(aType, codeSeg->iRootName);
Change() |= KDebuggerChangeCode;
break;
}
case EEventAddLibrary:
case EEventRemoveLibrary:
{
DLibrary* lib = (DLibrary*)a1;
interested = hdrPresent && DEventHandler::InterestedIn(aType, lib->iCodeSeg->iRootName);
Change() |= KDebuggerChangeLibrary;
break;
}
case EEventNewChunk:
case EEventUpdateChunk:
case EEventDeleteChunk:
{
DChunk* chunk = (DChunk*)a1;
//The chunk will not neccesarily have an owning process.
interested = hdrPresent && ( (!chunk->iOwningProcess && hdr->iFlags & TFilterHeader::EGlobalEvents) ||
(chunk->iOwningProcess && DEventHandler::InterestedIn(aType, *(chunk->iOwningProcess->iName))));
Change() |= KDebuggerChangeChunk;
break;
}
case EEventAddThread:
case EEventUpdateThread:
case EEventRemoveThread:
{
DThread* thread = (DThread*)a1;
interested = hdrPresent && DEventHandler::InterestedIn(aType, *(thread->iOwningProcess->iName));
Change() |= KDebuggerChangeThread;
break;
}
case EEventAddProcess:
case EEventUpdateProcess:
case EEventRemoveProcess:
{
DProcess* proc = (DProcess*)a1;
interested = hdrPresent && DEventHandler::InterestedIn(aType, *(proc->iName));
Change() |= KDebuggerChangeProcess;
break;
}
case EEventLoadLdd:
case EEventUnloadLdd:
{
DCodeSeg* codeSeg = (DCodeSeg*)a1;
interested = hdrPresent && DEventHandler::InterestedIn(aType, codeSeg->iRootName);
Change() |= KDebuggerChangeLdd;
break;
}
case EEventLoadPdd:
case EEventUnloadPdd:
{
DCodeSeg* codeSeg = (DCodeSeg*)a1;
interested = hdrPresent && DEventHandler::InterestedIn(aType, codeSeg->iRootName);
Change() |= KDebuggerChangePdd;
break;
}
case EEventSwExc:
case EEventHwExc:
{
DThread* thread = &Kern::CurrentThread();
interested = hdrPresent && DEventHandler::InterestedIn(aType, *(thread->iOwningProcess->iName));
// iChange variable not updated for compatibilty
break;
}
case EEventKillThread:
{
DThread* thread = (DThread*)a1;
interested = hdrPresent && DEventHandler::InterestedIn(aType, *(thread->iOwningProcess->iName));
// iChange variable not updated for compatibilty
break;
}
default:
break;
}
// If this event matches the mask, call the event handler
if (((1 << (aType & 31)) & TheDebuggerInfo->iEventMask[aType >> 5]) || interested)
{
__KTRACE_OPT(KDEBUGGER, Kern::Printf("KDebug: Calling debugger breakpoint-able handler for event type = 0x%x", aType));
DEventHandler* handler = (DEventHandler*)aThis;
ret = (*((TDebuggerEventHandler)handler->iHwChunk->iLinAddr))(aType, a1, a2);
}
TheDebuggerInfo->ReleaseFilterBuffer();
// Allow other handlers to see this event
return ret;
}
/**
This looks at the filter list and event type
event is of interest to the client.
@param aKernelEvent Event Type for notification
@return true if user is interested in this event
@pre Assumes there is a filter present and valid
*/
TBool DEventHandler::InterestedIn(const TKernelEvent& aKernelEvent, TDesC& aName)
{
TFilterHeader* hdr = (TFilterHeader*)TheDebuggerInfo->iFilterBuffer;
TUint8* pos = TheDebuggerInfo->iFilterBuffer + sizeof(TFilterHeader);
TUint i;
for(i = hdr->iNumItems; i != 0; --i)
{
TFilterObject* obj = (TFilterObject*)pos;
//Get the filter object name eg. helloworld.exe
TPtrC ptr(obj->iName, obj->iLength);
//Each bit in iEventMask maps onto each member of enum TKernelEvent. ie the Nth bit of iEvent indicates
//if we are interested in the Nth enum in TKernelEvent
TUint64 eventOfInterest = ((1ULL << aKernelEvent) & obj->iEventMask);
if(eventOfInterest && (aName.CompareF(ptr) == 0))
{
return ETrue;
}
pos += Align4(sizeof(TFilterObject) + obj->iLength -1);
}
//no matching filter object found and so not interested
return EFalse;
}
/**
Create the stop-mode debug API
*/
DDebuggerInfo::DDebuggerInfo()
: // initialise the debug tables
iObjectOffsetTable(&Debugger::ObjectOffsetTable[0]),
iObjectOffsetTableCount(EOffsetTableEntryMax),
iThreadContextTable(NThread::UserContextTables()),
// publish the version number
iVersion(Debugger::Version()),
iOSVersion(TVersion(KE32MajorVersionNumber, KE32MinorVersionNumber, KE32BuildVersionNumber)),
iStopModeExtension(NULL),
// initialise our other mebers
// iChange(0),
iContainers(Kern::Containers()),
iCodeSegLock(Kern::CodeSegLock()),
iCodeSegGlobalList(Kern::CodeSegList()),
iScheduler(TScheduler::Ptr()),
#ifdef __MEMMODEL_MOVING__
iMemoryModelType(EARMv5MMU),
#elif defined(__MEMMODEL_MULTIPLE__) || defined(__MEMMODEL_FLEXIBLE__)
iMemoryModelType(EARMv6MMU),
#endif
iMemModelObjectOffsetTable(&Debugger::VariantObjectOffsetTable[0]),
iMemModelObjectOffsetTableCount(sizeof(Debugger::VariantObjectOffsetTable)/sizeof(TInt)),
iFilterBuffer(NULL),
iFilterBufferSize(0),
iFilterBufferInUse(EFalse)
// iShadowPages(NULL),
// iShadowPageCount(0),
// iCurrentThread(NULL),
// iEventMask(),
// iEventHandlerBreakpoint(0)
{
}
/**
Locks access to the filter buffer by means of a boolean.
The debugger should read the iFilterBufferInUse variable to
see if it can write to the buffer
*/
inline void DDebuggerInfo::LockFilterBuffer()
{
iFilterBufferInUse = ETrue;
}
/**
Releases access to the filter buffer. If the debugger wishes to write to
the filter buffer and finds it to be currently in use, it should run to
this function to wait for access.
*/
void DDebuggerInfo::ReleaseFilterBuffer()
{
iFilterBufferInUse = EFalse;
}
/**
Install a stop-mode debugger
Make the stop-mode API visible to a JTAG debugger, by publishing its
existance in the superpage
*/
EXPORT_C TInt Debugger::Install(DDebuggerInfo* aDebugger)
{
Kern::SuperPage().iDebuggerInfo = aDebugger;
return KErrNone;
}
/**
Return the currently installed stop-mode API
*/
EXPORT_C DDebuggerInfo* Debugger::DebuggerInfo()
{
return Kern::SuperPage().iDebuggerInfo;
}
EXPORT_C TVersion Debugger::Version()
/**
Return the version of the debug API
*/
{
return TVersion(KDebuggerMajorVersionNumber, KDebuggerMinorVersionNumber, KDebuggerBuildVersionNumber);
}
/**
Extension entry point
Install a stop-mode debugger API
*/
DECLARE_STANDARD_EXTENSION()
{
__KTRACE_OPT(KBOOT, Kern::Printf("Starting debugger API"));
// Create debugger info
DDebuggerInfo* debugInfo = new DDebuggerInfo();
if (!debugInfo)
{
__KTRACE_OPT(KBOOT, Kern::Printf("Debugger API failed to start"));
return KErrNone;
}
TheDebuggerInfo = debugInfo;
// Install scheduler hooks
TInt err = InsertSchedulerHooks();
if (!err)
{
EnableRescheduleCallback();
}
else
{
__KTRACE_OPT(KBOOT, Kern::Printf("Debugger rescheduler hooks failed to start %d", err));
}
// Add event handler for updating change flags
DEventHandler* eventHandler = DEventHandler::New();
if (eventHandler)
{
err = eventHandler->Add();
}
else
{
err = KErrNoMemory;
}
if (err)
{
__KTRACE_OPT(KBOOT, Kern::Printf("Debugger change notifier failed to start %d", err));
}
//Allocate buffer for filter
TAny* req = Kern::AllocZ(KFilterBufferSize);
if(!req)
{
//This is not fatal, just means we can't filter data. Buffer is NULL
__KTRACE_OPT(KBOOT, Kern::Printf("Debugger failed to allocate filter buffer. Filtering is not enabled"));
}
else
{
debugInfo->iFilterBuffer = (TUint8*)req;
debugInfo->iFilterBufferSize = KFilterBufferSize;
}
// Publish debug info in the super page
err = Debugger::Install(debugInfo);
return err;
}