mmlr + bonefish:
Moved the static variables for managing the tracing buffer into a separate area. The area is mapped at one of a few possible physical addresses and can be found again when rebooting. This allows us to resurrect the tracing buffer from the previous session, which could help tremendously when tracking certain bugs (like triple faults). There's very little checking done yet, so it is probably not as robust as we would wish it to be. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31942 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -18,6 +18,7 @@
|
|||||||
#include <team.h>
|
#include <team.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
#include <util/AutoLock.h>
|
#include <util/AutoLock.h>
|
||||||
|
#include <vm.h>
|
||||||
|
|
||||||
|
|
||||||
struct tracing_stack_trace {
|
struct tracing_stack_trace {
|
||||||
@@ -47,13 +48,210 @@ enum {
|
|||||||
static const size_t kTraceOutputBufferSize = 10240;
|
static const size_t kTraceOutputBufferSize = 10240;
|
||||||
static const size_t kBufferSize = MAX_TRACE_SIZE / 4;
|
static const size_t kBufferSize = MAX_TRACE_SIZE / 4;
|
||||||
|
|
||||||
static trace_entry* sBuffer;
|
static const addr_t kMetaDataBaseAddress = 32 * 1024 * 1024;
|
||||||
static trace_entry* sFirstEntry;
|
static const addr_t kMetaDataBaseEndAddress = 128 * 1024 * 1024;
|
||||||
static trace_entry* sAfterLastEntry;
|
static const addr_t kMetaDataAddressIncrement = 8 * 1024 * 1024;
|
||||||
static uint32 sEntries;
|
static const uint32 kMetaDataMagic1 = 'Vali';
|
||||||
static uint32 sWritten;
|
static const uint32 kMetaDataMagic2 = 'dTra';
|
||||||
static spinlock sLock;
|
static const uint32 kMetaDataMagic3 = 'cing';
|
||||||
static char* sTraceOutputBuffer;
|
|
||||||
|
|
||||||
|
class TracingMetaData {
|
||||||
|
public:
|
||||||
|
uint32 magic1;
|
||||||
|
trace_entry* buffer;
|
||||||
|
trace_entry* firstEntry;
|
||||||
|
trace_entry* afterLastEntry;
|
||||||
|
uint32 entries;
|
||||||
|
uint32 magic2;
|
||||||
|
uint32 written;
|
||||||
|
spinlock lock;
|
||||||
|
char* traceOutputBuffer;
|
||||||
|
addr_t physicalAddress;
|
||||||
|
uint32 magic3;
|
||||||
|
|
||||||
|
static status_t Create(TracingMetaData*& _metaData)
|
||||||
|
{
|
||||||
|
// search meta data in memory (from previous session)
|
||||||
|
area_id area;
|
||||||
|
TracingMetaData* metaData;
|
||||||
|
status_t error = _CreateMetaDataArea(true, area, metaData);
|
||||||
|
if (error == B_OK) {
|
||||||
|
if (_InitPreviousTracingData(metaData)) {
|
||||||
|
_metaData = metaData;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
dprintf("Found previous tracing meta data, but failed to init.\n");
|
||||||
|
|
||||||
|
// invalidate the meta data
|
||||||
|
metaData->magic1 = 0;
|
||||||
|
metaData->magic2 = 0;
|
||||||
|
metaData->magic3 = 0;
|
||||||
|
delete_area(area);
|
||||||
|
} else
|
||||||
|
dprintf("No previous tracing meta data found.\n");
|
||||||
|
|
||||||
|
// no previous tracng data found -- create new one
|
||||||
|
error = _CreateMetaDataArea(false, area, metaData);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
area = create_area("tracing log",
|
||||||
|
(void**)&metaData->traceOutputBuffer, B_ANY_KERNEL_ADDRESS,
|
||||||
|
kTraceOutputBufferSize + MAX_TRACE_SIZE, B_CONTIGUOUS,
|
||||||
|
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
||||||
|
if (area < 0)
|
||||||
|
return area;
|
||||||
|
|
||||||
|
// get the physical address
|
||||||
|
physical_entry physicalEntry;
|
||||||
|
if (get_memory_map(metaData->traceOutputBuffer, B_PAGE_SIZE,
|
||||||
|
&physicalEntry, 1) == B_OK) {
|
||||||
|
metaData->physicalAddress = (addr_t)physicalEntry.address;
|
||||||
|
} else {
|
||||||
|
dprintf("TracingMetaData::Create(): failed to get physical address "
|
||||||
|
"of tracing buffer\n");
|
||||||
|
metaData->physicalAddress = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
metaData->buffer = (trace_entry*)(metaData->traceOutputBuffer
|
||||||
|
+ kTraceOutputBufferSize);
|
||||||
|
metaData->firstEntry = metaData->buffer;
|
||||||
|
metaData->afterLastEntry = metaData->buffer;
|
||||||
|
|
||||||
|
metaData->entries = 0;
|
||||||
|
metaData->written = 0;
|
||||||
|
B_INITIALIZE_SPINLOCK(&metaData->lock);
|
||||||
|
|
||||||
|
metaData->magic1 = kMetaDataMagic1;
|
||||||
|
metaData->magic2 = kMetaDataMagic2;
|
||||||
|
metaData->magic3 = kMetaDataMagic3;
|
||||||
|
|
||||||
|
_metaData = metaData;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static status_t _CreateMetaDataArea(bool findPrevious,
|
||||||
|
area_id& _area, TracingMetaData*& _metaData)
|
||||||
|
{
|
||||||
|
// search meta data in memory (from previous session)
|
||||||
|
TracingMetaData* metaData;
|
||||||
|
addr_t metaDataAddress = kMetaDataBaseAddress;
|
||||||
|
for (; metaDataAddress <= kMetaDataBaseEndAddress;
|
||||||
|
metaDataAddress += kMetaDataAddressIncrement) {
|
||||||
|
area_id area = create_area_etc(B_SYSTEM_TEAM, "tracing metadata",
|
||||||
|
(void**)&metaData, B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE,
|
||||||
|
B_FULL_LOCK, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
|
||||||
|
metaDataAddress, CREATE_AREA_DONT_CLEAR);
|
||||||
|
if (area < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!findPrevious) {
|
||||||
|
_area = area;
|
||||||
|
_metaData = metaData;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (metaData->magic1 == kMetaDataMagic1
|
||||||
|
&& metaData->magic2 == kMetaDataMagic2
|
||||||
|
&& metaData->magic3 == kMetaDataMagic3) {
|
||||||
|
_area = area;
|
||||||
|
_metaData = metaData;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete_area(area);
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool _InitPreviousTracingData(TracingMetaData* metaData)
|
||||||
|
{
|
||||||
|
addr_t bufferStart
|
||||||
|
= (addr_t)metaData->traceOutputBuffer + kTraceOutputBufferSize;
|
||||||
|
addr_t bufferEnd = bufferStart + MAX_TRACE_SIZE;
|
||||||
|
|
||||||
|
if (bufferStart > bufferEnd || (addr_t)metaData->buffer != bufferStart
|
||||||
|
|| (addr_t)metaData->firstEntry < bufferStart
|
||||||
|
|| (addr_t)metaData->firstEntry + sizeof(trace_entry) >= bufferEnd
|
||||||
|
|| (addr_t)metaData->afterLastEntry < bufferStart
|
||||||
|
|| (addr_t)metaData->afterLastEntry > bufferEnd
|
||||||
|
|| metaData->physicalAddress == 0) {
|
||||||
|
dprintf("Failed to init tracing meta data: Sanity checks "
|
||||||
|
"failed.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// re-map the previous tracing buffer
|
||||||
|
void* buffer = metaData->traceOutputBuffer;
|
||||||
|
area_id area = create_area_etc(B_SYSTEM_TEAM, "tracing log",
|
||||||
|
&buffer, B_EXACT_ADDRESS, kTraceOutputBufferSize + MAX_TRACE_SIZE,
|
||||||
|
B_CONTIGUOUS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
|
||||||
|
metaData->physicalAddress, CREATE_AREA_DONT_CLEAR);
|
||||||
|
if (area < 0) {
|
||||||
|
dprintf("Failed to init tracing meta data: Mapping tracing log "
|
||||||
|
"buffer failed: %s\n", strerror(area));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: More checks:
|
||||||
|
// * tracing entry counts
|
||||||
|
// * tracing entries (linked list)
|
||||||
|
// * tracing entries objects (vtables)
|
||||||
|
|
||||||
|
B_INITIALIZE_SPINLOCK(&metaData->lock);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static TracingMetaData* sTracingMetaData;
|
||||||
|
static TracingMetaData sDummyTracingMetaData;
|
||||||
|
|
||||||
|
|
||||||
|
static inline trace_entry*
|
||||||
|
Buffer()
|
||||||
|
{
|
||||||
|
return sTracingMetaData->buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline trace_entry*&
|
||||||
|
FirstEntry()
|
||||||
|
{
|
||||||
|
return sTracingMetaData->firstEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline trace_entry*&
|
||||||
|
AfterLastEntry()
|
||||||
|
{
|
||||||
|
return sTracingMetaData->afterLastEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline uint32&
|
||||||
|
Entries()
|
||||||
|
{
|
||||||
|
return sTracingMetaData->entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline uint32&
|
||||||
|
Written()
|
||||||
|
{
|
||||||
|
return sTracingMetaData->written;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline spinlock&
|
||||||
|
Lock()
|
||||||
|
{
|
||||||
|
return sTracingMetaData->lock;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static trace_entry*
|
static trace_entry*
|
||||||
@@ -61,9 +259,9 @@ next_entry(trace_entry* entry)
|
|||||||
{
|
{
|
||||||
entry += entry->size;
|
entry += entry->size;
|
||||||
if ((entry->flags & WRAP_ENTRY) != 0)
|
if ((entry->flags & WRAP_ENTRY) != 0)
|
||||||
entry = sBuffer;
|
entry = Buffer();
|
||||||
|
|
||||||
if (entry == sAfterLastEntry)
|
if (entry == AfterLastEntry())
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return entry;
|
return entry;
|
||||||
@@ -73,12 +271,12 @@ next_entry(trace_entry* entry)
|
|||||||
static trace_entry*
|
static trace_entry*
|
||||||
previous_entry(trace_entry* entry)
|
previous_entry(trace_entry* entry)
|
||||||
{
|
{
|
||||||
if (entry == sFirstEntry)
|
if (entry == FirstEntry())
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (entry == sBuffer) {
|
if (entry == Buffer()) {
|
||||||
// beginning of buffer -- previous entry is a wrap entry
|
// beginning of buffer -- previous entry is a wrap entry
|
||||||
entry = sBuffer + kBufferSize - entry->previous_size;
|
entry = Buffer() + kBufferSize - entry->previous_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
return entry - entry->previous_size;
|
return entry - entry->previous_size;
|
||||||
@@ -88,16 +286,16 @@ previous_entry(trace_entry* entry)
|
|||||||
static bool
|
static bool
|
||||||
free_first_entry()
|
free_first_entry()
|
||||||
{
|
{
|
||||||
TRACE((" skip start %p, %lu*4 bytes\n", sFirstEntry, sFirstEntry->size));
|
TRACE((" skip start %p, %lu*4 bytes\n", FirstEntry(), FirstEntry()->size));
|
||||||
|
|
||||||
trace_entry* newFirst = next_entry(sFirstEntry);
|
trace_entry* newFirst = next_entry(FirstEntry());
|
||||||
|
|
||||||
if (sFirstEntry->flags & BUFFER_ENTRY) {
|
if (FirstEntry()->flags & BUFFER_ENTRY) {
|
||||||
// a buffer entry -- just skip it
|
// a buffer entry -- just skip it
|
||||||
} else if (sFirstEntry->flags & ENTRY_INITIALIZED) {
|
} else if (FirstEntry()->flags & ENTRY_INITIALIZED) {
|
||||||
// fully initialized TraceEntry -- destroy it
|
// fully initialized TraceEntry -- destroy it
|
||||||
TraceEntry::FromTraceEntry(sFirstEntry)->~TraceEntry();
|
TraceEntry::FromTraceEntry(FirstEntry())->~TraceEntry();
|
||||||
sEntries--;
|
Entries()--;
|
||||||
} else {
|
} else {
|
||||||
// Not fully initialized TraceEntry. We can't free it, since
|
// Not fully initialized TraceEntry. We can't free it, since
|
||||||
// then it's constructor might still write into the memory and
|
// then it's constructor might still write into the memory and
|
||||||
@@ -107,74 +305,74 @@ free_first_entry()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (newFirst == NULL) {
|
if (newFirst == NULL) {
|
||||||
// everything is freed -- that practically this can't happen, if
|
// everything is freed -- practically this can't happen, if
|
||||||
// the buffer is large enough to hold three max-sized entries
|
// the buffer is large enough to hold three max-sized entries
|
||||||
sFirstEntry = sAfterLastEntry = sBuffer;
|
FirstEntry() = AfterLastEntry() = Buffer();
|
||||||
TRACE(("free_first_entry(): all entries freed!\n"));
|
TRACE(("free_first_entry(): all entries freed!\n"));
|
||||||
} else
|
} else
|
||||||
sFirstEntry = newFirst;
|
FirstEntry() = newFirst;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Makes sure we have needed * 4 bytes of memory at sAfterLastEntry.
|
/*! Makes sure we have needed * 4 bytes of memory at AfterLastEntry().
|
||||||
Returns \c false, if unable to free that much.
|
Returns \c false, if unable to free that much.
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
make_space(size_t needed)
|
make_space(size_t needed)
|
||||||
{
|
{
|
||||||
// we need space for sAfterLastEntry, too (in case we need to wrap around
|
// we need space for AfterLastEntry(), too (in case we need to wrap around
|
||||||
// later)
|
// later)
|
||||||
needed++;
|
needed++;
|
||||||
|
|
||||||
// If there's not enough space (free or occupied) after sAfterLastEntry,
|
// If there's not enough space (free or occupied) after AfterLastEntry(),
|
||||||
// we free all entries in that region and wrap around.
|
// we free all entries in that region and wrap around.
|
||||||
if (sAfterLastEntry + needed > sBuffer + kBufferSize) {
|
if (AfterLastEntry() + needed > Buffer() + kBufferSize) {
|
||||||
TRACE(("make_space(%lu), wrapping around: after last: %p\n", needed,
|
TRACE(("make_space(%lu), wrapping around: after last: %p\n", needed,
|
||||||
sAfterLastEntry));
|
AfterLastEntry()));
|
||||||
|
|
||||||
// Free all entries after sAfterLastEntry and one more at the beginning
|
// Free all entries after AfterLastEntry() and one more at the beginning
|
||||||
// of the buffer.
|
// of the buffer.
|
||||||
while (sFirstEntry > sAfterLastEntry) {
|
while (FirstEntry() > AfterLastEntry()) {
|
||||||
if (!free_first_entry())
|
if (!free_first_entry())
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (sAfterLastEntry != sBuffer && !free_first_entry())
|
if (AfterLastEntry() != Buffer() && !free_first_entry())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// just in case free_first_entry() freed the very last existing entry
|
// just in case free_first_entry() freed the very last existing entry
|
||||||
if (sAfterLastEntry == sBuffer)
|
if (AfterLastEntry() == Buffer())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// mark as wrap entry and actually wrap around
|
// mark as wrap entry and actually wrap around
|
||||||
trace_entry* wrapEntry = sAfterLastEntry;
|
trace_entry* wrapEntry = AfterLastEntry();
|
||||||
wrapEntry->size = 0;
|
wrapEntry->size = 0;
|
||||||
wrapEntry->flags = WRAP_ENTRY;
|
wrapEntry->flags = WRAP_ENTRY;
|
||||||
sAfterLastEntry = sBuffer;
|
AfterLastEntry() = Buffer();
|
||||||
sAfterLastEntry->previous_size = sBuffer + kBufferSize - wrapEntry;
|
AfterLastEntry()->previous_size = Buffer() + kBufferSize - wrapEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sFirstEntry <= sAfterLastEntry) {
|
if (FirstEntry() <= AfterLastEntry()) {
|
||||||
// buffer is empty or the space after sAfterLastEntry is unoccupied
|
// buffer is empty or the space after AfterLastEntry() is unoccupied
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// free the first entries, until there's enough space
|
// free the first entries, until there's enough space
|
||||||
size_t space = sFirstEntry - sAfterLastEntry;
|
size_t space = FirstEntry() - AfterLastEntry();
|
||||||
|
|
||||||
if (space < needed) {
|
if (space < needed) {
|
||||||
TRACE(("make_space(%lu), left %ld\n", needed, space));
|
TRACE(("make_space(%lu), left %ld\n", needed, space));
|
||||||
}
|
}
|
||||||
|
|
||||||
while (space < needed) {
|
while (space < needed) {
|
||||||
space += sFirstEntry->size;
|
space += FirstEntry()->size;
|
||||||
|
|
||||||
if (!free_first_entry())
|
if (!free_first_entry())
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE((" out: start %p, entries %ld\n", sFirstEntry, sEntries));
|
TRACE((" out: start %p, entries %ld\n", FirstEntry(), Entries()));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -183,31 +381,31 @@ make_space(size_t needed)
|
|||||||
static trace_entry*
|
static trace_entry*
|
||||||
allocate_entry(size_t size, uint16 flags)
|
allocate_entry(size_t size, uint16 flags)
|
||||||
{
|
{
|
||||||
if (sAfterLastEntry == NULL || size == 0 || size >= 65532)
|
if (AfterLastEntry() == NULL || size == 0 || size >= 65532)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
InterruptsSpinLocker _(sLock);
|
InterruptsSpinLocker _(Lock());
|
||||||
|
|
||||||
size = (size + 3) >> 2;
|
size = (size + 3) >> 2;
|
||||||
// 4 byte aligned, don't store the lower 2 bits
|
// 4 byte aligned, don't store the lower 2 bits
|
||||||
|
|
||||||
TRACE(("allocate_entry(%lu), start %p, end %p, buffer %p\n", size * 4,
|
TRACE(("allocate_entry(%lu), start %p, end %p, buffer %p\n", size * 4,
|
||||||
sFirstEntry, sAfterLastEntry, sBuffer));
|
FirstEntry(), AfterLastEntry(), Buffer()));
|
||||||
|
|
||||||
if (!make_space(size))
|
if (!make_space(size))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
trace_entry* entry = sAfterLastEntry;
|
trace_entry* entry = AfterLastEntry();
|
||||||
entry->size = size;
|
entry->size = size;
|
||||||
entry->flags = flags;
|
entry->flags = flags;
|
||||||
sAfterLastEntry += size;
|
AfterLastEntry() += size;
|
||||||
sAfterLastEntry->previous_size = size;
|
AfterLastEntry()->previous_size = size;
|
||||||
|
|
||||||
if (!(flags & BUFFER_ENTRY))
|
if (!(flags & BUFFER_ENTRY))
|
||||||
sEntries++;
|
Entries()++;
|
||||||
|
|
||||||
TRACE((" entry: %p, end %p, start %p, entries %ld\n", entry,
|
TRACE((" entry: %p, end %p, start %p, entries %ld\n", entry,
|
||||||
sAfterLastEntry, sFirstEntry, sEntries));
|
AfterLastEntry(), FirstEntry(), Entries()));
|
||||||
|
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
@@ -327,7 +525,7 @@ TraceEntry::Initialized()
|
|||||||
{
|
{
|
||||||
#if ENABLE_TRACING
|
#if ENABLE_TRACING
|
||||||
ToTraceEntry()->flags |= ENTRY_INITIALIZED;
|
ToTraceEntry()->flags |= ENTRY_INITIALIZED;
|
||||||
sWritten++;
|
Written()++;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -456,6 +654,20 @@ class UserTraceEntry : public AbstractTraceEntry {
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class TracingLogStartEntry : public AbstractTraceEntry {
|
||||||
|
public:
|
||||||
|
TracingLogStartEntry()
|
||||||
|
{
|
||||||
|
Initialized();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void AddDump(TraceOutput& out)
|
||||||
|
{
|
||||||
|
out.Print("ktrace start");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#endif // ENABLE_TRACING
|
#endif // ENABLE_TRACING
|
||||||
|
|
||||||
|
|
||||||
@@ -715,7 +927,7 @@ TraceEntry*
|
|||||||
TraceEntryIterator::Next()
|
TraceEntryIterator::Next()
|
||||||
{
|
{
|
||||||
if (fIndex == 0) {
|
if (fIndex == 0) {
|
||||||
fEntry = _NextNonBufferEntry(sFirstEntry);
|
fEntry = _NextNonBufferEntry(FirstEntry());
|
||||||
fIndex = 1;
|
fIndex = 1;
|
||||||
} else if (fEntry != NULL) {
|
} else if (fEntry != NULL) {
|
||||||
fEntry = _NextNonBufferEntry(next_entry(fEntry));
|
fEntry = _NextNonBufferEntry(next_entry(fEntry));
|
||||||
@@ -729,8 +941,8 @@ TraceEntryIterator::Next()
|
|||||||
TraceEntry*
|
TraceEntry*
|
||||||
TraceEntryIterator::Previous()
|
TraceEntryIterator::Previous()
|
||||||
{
|
{
|
||||||
if (fIndex == (int32)sEntries + 1)
|
if (fIndex == (int32)Entries() + 1)
|
||||||
fEntry = sAfterLastEntry;
|
fEntry = AfterLastEntry();
|
||||||
|
|
||||||
if (fEntry != NULL) {
|
if (fEntry != NULL) {
|
||||||
fEntry = _PreviousNonBufferEntry(previous_entry(fEntry));
|
fEntry = _PreviousNonBufferEntry(previous_entry(fEntry));
|
||||||
@@ -747,8 +959,8 @@ TraceEntryIterator::MoveTo(int32 index)
|
|||||||
if (index == fIndex)
|
if (index == fIndex)
|
||||||
return Current();
|
return Current();
|
||||||
|
|
||||||
if (index <= 0 || index > (int32)sEntries) {
|
if (index <= 0 || index > (int32)Entries()) {
|
||||||
fIndex = (index <= 0 ? 0 : sEntries + 1);
|
fIndex = (index <= 0 ? 0 : Entries() + 1);
|
||||||
fEntry = NULL;
|
fEntry = NULL;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -764,11 +976,11 @@ TraceEntryIterator::MoveTo(int32 index)
|
|||||||
fEntry = NULL;
|
fEntry = NULL;
|
||||||
fIndex = 0;
|
fIndex = 0;
|
||||||
}
|
}
|
||||||
if ((int32)sEntries + 1 - fIndex < distance) {
|
if ((int32)Entries() + 1 - fIndex < distance) {
|
||||||
distance = sEntries + 1 - fIndex;
|
distance = Entries() + 1 - fIndex;
|
||||||
direction = -1;
|
direction = -1;
|
||||||
fEntry = NULL;
|
fEntry = NULL;
|
||||||
fIndex = sEntries + 1;
|
fIndex = Entries() + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// iterate to the index
|
// iterate to the index
|
||||||
@@ -822,7 +1034,7 @@ dump_tracing_internal(int argc, char** argv, WrapperTraceFilter* wrapperFilter)
|
|||||||
static uint32 _previousOutputFlags = 0;
|
static uint32 _previousOutputFlags = 0;
|
||||||
static TraceEntryIterator iterator;
|
static TraceEntryIterator iterator;
|
||||||
|
|
||||||
// Note: start and index are Pascal-like indices (i.e. in [1, sEntries]).
|
// Note: start and index are Pascal-like indices (i.e. in [1, Entries()]).
|
||||||
int32 start = 0; // special index: print the last count entries
|
int32 start = 0; // special index: print the last count entries
|
||||||
int32 count = 0;
|
int32 count = 0;
|
||||||
int32 maxToCheck = 0;
|
int32 maxToCheck = 0;
|
||||||
@@ -862,8 +1074,8 @@ dump_tracing_internal(int argc, char** argv, WrapperTraceFilter* wrapperFilter)
|
|||||||
print_debugger_command_usage(argv[0]);
|
print_debugger_command_usage(argv[0]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (sWritten == 0 || sWritten != _previousWritten
|
if (Written() == 0 || Written() != _previousWritten
|
||||||
|| sEntries != _previousEntries) {
|
|| Entries() != _previousEntries) {
|
||||||
kprintf("Can't continue iteration. \"%s\" has not been invoked "
|
kprintf("Can't continue iteration. \"%s\" has not been invoked "
|
||||||
"before, or there were new entries written since the last "
|
"before, or there were new entries written since the last "
|
||||||
"invocation.\n", argv[0]);
|
"invocation.\n", argv[0]);
|
||||||
@@ -921,7 +1133,7 @@ dump_tracing_internal(int argc, char** argv, WrapperTraceFilter* wrapperFilter)
|
|||||||
if (maxToCheck == 0 || !hasFilter)
|
if (maxToCheck == 0 || !hasFilter)
|
||||||
maxToCheck = count;
|
maxToCheck = count;
|
||||||
else if (maxToCheck < 0)
|
else if (maxToCheck < 0)
|
||||||
maxToCheck = sEntries;
|
maxToCheck = Entries();
|
||||||
|
|
||||||
// determine iteration direction
|
// determine iteration direction
|
||||||
direction = (start <= 0 || count < 0 ? -1 : 1);
|
direction = (start <= 0 || count < 0 ? -1 : 1);
|
||||||
@@ -931,14 +1143,14 @@ dump_tracing_internal(int argc, char** argv, WrapperTraceFilter* wrapperFilter)
|
|||||||
count = -count;
|
count = -count;
|
||||||
if (maxToCheck < 0)
|
if (maxToCheck < 0)
|
||||||
maxToCheck = -maxToCheck;
|
maxToCheck = -maxToCheck;
|
||||||
if (maxToCheck > (int32)sEntries)
|
if (maxToCheck > (int32)Entries())
|
||||||
maxToCheck = sEntries;
|
maxToCheck = Entries();
|
||||||
if (count > maxToCheck)
|
if (count > maxToCheck)
|
||||||
count = maxToCheck;
|
count = maxToCheck;
|
||||||
|
|
||||||
// validate start
|
// validate start
|
||||||
if (start <= 0 || start > (int32)sEntries)
|
if (start <= 0 || start > (int32)Entries())
|
||||||
start = max_c(1, sEntries);
|
start = max_c(1, Entries());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (direction < 0) {
|
if (direction < 0) {
|
||||||
@@ -946,17 +1158,17 @@ dump_tracing_internal(int argc, char** argv, WrapperTraceFilter* wrapperFilter)
|
|||||||
lastToCheck = start;
|
lastToCheck = start;
|
||||||
} else {
|
} else {
|
||||||
firstToCheck = start;
|
firstToCheck = start;
|
||||||
lastToCheck = min_c((int32)sEntries, start + maxToCheck - 1);
|
lastToCheck = min_c((int32)Entries(), start + maxToCheck - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset the iterator, if something changed in the meantime
|
// reset the iterator, if something changed in the meantime
|
||||||
if (sWritten == 0 || sWritten != _previousWritten
|
if (Written() == 0 || Written() != _previousWritten
|
||||||
|| sEntries != _previousEntries) {
|
|| Entries() != _previousEntries) {
|
||||||
iterator.Reset();
|
iterator.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
LazyTraceOutput out(sTraceOutputBuffer, kTraceOutputBufferSize,
|
LazyTraceOutput out(sTracingMetaData->traceOutputBuffer,
|
||||||
outputFlags);
|
kTraceOutputBufferSize, outputFlags);
|
||||||
|
|
||||||
bool markedMatching = false;
|
bool markedMatching = false;
|
||||||
int32 firstToDump = firstToCheck;
|
int32 firstToDump = firstToCheck;
|
||||||
@@ -1059,7 +1271,7 @@ dump_tracing_internal(int argc, char** argv, WrapperTraceFilter* wrapperFilter)
|
|||||||
|
|
||||||
kprintf("printed %ld entries within range %ld to %ld (%ld of %ld total, "
|
kprintf("printed %ld entries within range %ld to %ld (%ld of %ld total, "
|
||||||
"%ld ever)\n", dumped, firstToCheck, lastToCheck,
|
"%ld ever)\n", dumped, firstToCheck, lastToCheck,
|
||||||
lastToCheck - firstToCheck + 1, sEntries, sWritten);
|
lastToCheck - firstToCheck + 1, Entries(), Written());
|
||||||
|
|
||||||
// store iteration state
|
// store iteration state
|
||||||
_previousCount = count;
|
_previousCount = count;
|
||||||
@@ -1069,8 +1281,8 @@ dump_tracing_internal(int argc, char** argv, WrapperTraceFilter* wrapperFilter)
|
|||||||
_previousFirstChecked = firstToCheck;
|
_previousFirstChecked = firstToCheck;
|
||||||
_previousLastChecked = lastToCheck;
|
_previousLastChecked = lastToCheck;
|
||||||
_previousDirection = direction;
|
_previousDirection = direction;
|
||||||
_previousWritten = sWritten;
|
_previousWritten = Written();
|
||||||
_previousEntries = sEntries;
|
_previousEntries = Entries();
|
||||||
_previousOutputFlags = outputFlags;
|
_previousOutputFlags = outputFlags;
|
||||||
|
|
||||||
return cont != 0 ? B_KDEBUG_CONT : 0;
|
return cont != 0 ? B_KDEBUG_CONT : 0;
|
||||||
@@ -1197,7 +1409,7 @@ void
|
|||||||
lock_tracing_buffer()
|
lock_tracing_buffer()
|
||||||
{
|
{
|
||||||
#if ENABLE_TRACING
|
#if ENABLE_TRACING
|
||||||
acquire_spinlock(&sLock);
|
acquire_spinlock(&Lock());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1206,7 +1418,7 @@ void
|
|||||||
unlock_tracing_buffer()
|
unlock_tracing_buffer()
|
||||||
{
|
{
|
||||||
#if ENABLE_TRACING
|
#if ENABLE_TRACING
|
||||||
release_spinlock(&sLock);
|
release_spinlock(&Lock());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1215,15 +1427,13 @@ extern "C" status_t
|
|||||||
tracing_init(void)
|
tracing_init(void)
|
||||||
{
|
{
|
||||||
#if ENABLE_TRACING
|
#if ENABLE_TRACING
|
||||||
area_id area = create_area("tracing log", (void**)&sTraceOutputBuffer,
|
status_t result = TracingMetaData::Create(sTracingMetaData);
|
||||||
B_ANY_KERNEL_ADDRESS, MAX_TRACE_SIZE + kTraceOutputBufferSize,
|
if (result != B_OK) {
|
||||||
B_FULL_LOCK, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
sTracingMetaData = &sDummyTracingMetaData;
|
||||||
if (area < B_OK)
|
return result;
|
||||||
return area;
|
}
|
||||||
|
|
||||||
sBuffer = (trace_entry*)(sTraceOutputBuffer + kTraceOutputBufferSize);
|
new(nothrow) TracingLogStartEntry();
|
||||||
sFirstEntry = sBuffer;
|
|
||||||
sAfterLastEntry = sBuffer;
|
|
||||||
|
|
||||||
add_debugger_command_etc("traced", &dump_tracing_command,
|
add_debugger_command_etc("traced", &dump_tracing_command,
|
||||||
"Dump recorded trace entries",
|
"Dump recorded trace entries",
|
||||||
|
|||||||
Reference in New Issue
Block a user