* Fixed my fix for make_space() wrapping. It's always a good idea to
write code aligned to what one has written in the comment (or the
other way around).
* Made trace_entry structure doubly linked, by introducing a
previous_size member. By using bit fields, shrinking the flags field
to 4 bits, and not saving the lower two bits of size and previous_size
(which are always 0 due to alignment), the structure remains 4 byte
sized and can still address the same entry size.
* kBufferSize is no longer one less than it could be.
* "traced" command:
- Use static variable for the iteration state rather then cluttering
the temporary debug variable name space.
- The <count> parameter can now be negative, in which case the entries
before (and including) <start> are printed.
- Added a new optional parameter, specifying the maximal number of
entries to be filtered. Filtered iteration is beautifully
comfortable now.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23678 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -11,8 +11,9 @@
|
|||||||
|
|
||||||
|
|
||||||
struct trace_entry {
|
struct trace_entry {
|
||||||
uint16 size;
|
uint32 size : 14; // actual size is *4
|
||||||
uint16 flags;
|
uint32 previous_size : 14; // actual size is *4
|
||||||
|
uint32 flags : 4;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
@@ -37,7 +38,7 @@ class TraceOutput {
|
|||||||
size_t fSize;
|
size_t fSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TraceEntry : trace_entry {
|
class TraceEntry : public trace_entry {
|
||||||
public:
|
public:
|
||||||
TraceEntry();
|
TraceEntry();
|
||||||
virtual ~TraceEntry();
|
virtual ~TraceEntry();
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ enum {
|
|||||||
BUFFER_ENTRY = 0x04
|
BUFFER_ENTRY = 0x04
|
||||||
};
|
};
|
||||||
|
|
||||||
static const size_t kBufferSize = MAX_TRACE_SIZE / 4 - 1;
|
static const size_t kBufferSize = MAX_TRACE_SIZE / 4;
|
||||||
|
|
||||||
static trace_entry* sBuffer;
|
static trace_entry* sBuffer;
|
||||||
static trace_entry* sFirstEntry;
|
static trace_entry* sFirstEntry;
|
||||||
@@ -44,7 +44,7 @@ static spinlock sLock;
|
|||||||
static trace_entry*
|
static trace_entry*
|
||||||
next_entry(trace_entry* entry)
|
next_entry(trace_entry* entry)
|
||||||
{
|
{
|
||||||
entry += entry->size >> 2;
|
entry += entry->size;
|
||||||
if ((entry->flags & WRAP_ENTRY) != 0)
|
if ((entry->flags & WRAP_ENTRY) != 0)
|
||||||
entry = sBuffer;
|
entry = sBuffer;
|
||||||
|
|
||||||
@@ -55,10 +55,25 @@ next_entry(trace_entry* entry)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static trace_entry*
|
||||||
|
previous_entry(trace_entry* entry)
|
||||||
|
{
|
||||||
|
if (entry == sFirstEntry)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (entry == sBuffer) {
|
||||||
|
// beginning of buffer -- previous entry is a wrap entry
|
||||||
|
entry = sBuffer + kBufferSize - entry->previous_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return entry - entry->previous_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
free_first_entry()
|
free_first_entry()
|
||||||
{
|
{
|
||||||
TRACE((" skip start %p, %u bytes\n", sFirstEntry, sFirstEntry->size));
|
TRACE((" skip start %p, %lu*4 bytes\n", sFirstEntry, sFirstEntry->size));
|
||||||
|
|
||||||
trace_entry* newFirst = next_entry(sFirstEntry);
|
trace_entry* newFirst = next_entry(sFirstEntry);
|
||||||
|
|
||||||
@@ -88,34 +103,41 @@ free_first_entry()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Makes sure we have needed * 4 bytes of memory at sAfterLastEntry.
|
||||||
|
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 sAfterLastEntry, too (in case we need to wrap around
|
||||||
// later)
|
// later)
|
||||||
needed += 4;
|
needed++;
|
||||||
|
|
||||||
// If there's not enough space (free or occupied) after sAfterLastEntry,
|
// If there's not enough space (free or occupied) after sAfterLastEntry,
|
||||||
// we free all entries in that region and wrap around.
|
// we free all entries in that region and wrap around.
|
||||||
if (sAfterLastEntry + needed / 4 > sBuffer + kBufferSize) {
|
if (sAfterLastEntry + needed > sBuffer + kBufferSize) {
|
||||||
TRACE(("make_space(%lu), wrapping around: after last: %p\n", needed,
|
TRACE(("make_space(%lu), wrapping around: after last: %p\n", needed,
|
||||||
sAfterLastEntry));
|
sAfterLastEntry));
|
||||||
|
|
||||||
// Free all entries after sAfterLastEntry and one more at the beginning
|
// Free all entries after sAfterLastEntry and one more at the beginning
|
||||||
// of the buffer.
|
// of the buffer.
|
||||||
do {
|
while (sFirstEntry > sAfterLastEntry) {
|
||||||
if (!free_first_entry())
|
if (!free_first_entry())
|
||||||
return false;
|
return false;
|
||||||
} while (sFirstEntry > sAfterLastEntry);
|
}
|
||||||
|
if (sAfterLastEntry != sBuffer && !free_first_entry())
|
||||||
|
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 (sAfterLastEntry == sBuffer)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// mark as wrap entry and actually wrap around
|
// mark as wrap entry and actually wrap around
|
||||||
sAfterLastEntry->size = 0;
|
trace_entry* wrapEntry = sAfterLastEntry;
|
||||||
sAfterLastEntry->flags = WRAP_ENTRY;
|
wrapEntry->size = 0;
|
||||||
|
wrapEntry->flags = WRAP_ENTRY;
|
||||||
sAfterLastEntry = sBuffer;
|
sAfterLastEntry = sBuffer;
|
||||||
|
sAfterLastEntry->previous_size = sBuffer + kBufferSize - wrapEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sFirstEntry <= sAfterLastEntry) {
|
if (sFirstEntry <= sAfterLastEntry) {
|
||||||
@@ -124,7 +146,7 @@ make_space(size_t needed)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// free the first entries, until there's enough space
|
// free the first entries, until there's enough space
|
||||||
size_t space = (sFirstEntry - sAfterLastEntry) * 4;
|
size_t space = sFirstEntry - sAfterLastEntry;
|
||||||
|
|
||||||
if (space < needed) {
|
if (space < needed) {
|
||||||
TRACE(("make_space(%lu), left %ld\n", needed, space));
|
TRACE(("make_space(%lu), left %ld\n", needed, space));
|
||||||
@@ -151,9 +173,10 @@ allocate_entry(size_t size, uint16 flags)
|
|||||||
|
|
||||||
InterruptsSpinLocker _(sLock);
|
InterruptsSpinLocker _(sLock);
|
||||||
|
|
||||||
size = (size + 3) & ~3;
|
size = (size + 3) >> 2;
|
||||||
|
// 4 byte aligned, don't store the lower 2 bits
|
||||||
|
|
||||||
TRACE(("allocate_entry(%lu), start %p, end %p, buffer %p\n", size,
|
TRACE(("allocate_entry(%lu), start %p, end %p, buffer %p\n", size * 4,
|
||||||
sFirstEntry, sAfterLastEntry, sBuffer));
|
sFirstEntry, sAfterLastEntry, sBuffer));
|
||||||
|
|
||||||
if (!make_space(size))
|
if (!make_space(size))
|
||||||
@@ -162,7 +185,8 @@ allocate_entry(size_t size, uint16 flags)
|
|||||||
trace_entry* entry = sAfterLastEntry;
|
trace_entry* entry = sAfterLastEntry;
|
||||||
entry->size = size;
|
entry->size = size;
|
||||||
entry->flags = flags;
|
entry->flags = flags;
|
||||||
sAfterLastEntry += size >> 2;
|
sAfterLastEntry += size;
|
||||||
|
sAfterLastEntry->previous_size = size;
|
||||||
|
|
||||||
if (!(flags & BUFFER_ENTRY))
|
if (!(flags & BUFFER_ENTRY))
|
||||||
sEntries++;
|
sEntries++;
|
||||||
@@ -484,14 +508,132 @@ TraceFilterParser TraceFilterParser::sParser;
|
|||||||
#if ENABLE_TRACING
|
#if ENABLE_TRACING
|
||||||
|
|
||||||
|
|
||||||
|
class TraceEntryIterator {
|
||||||
|
public:
|
||||||
|
TraceEntryIterator(bool startFront)
|
||||||
|
:
|
||||||
|
fEntry(NULL),
|
||||||
|
fIndex(startFront ? 0 : sEntries + 1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 Index() const
|
||||||
|
{
|
||||||
|
return fIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
TraceEntry* Current() const
|
||||||
|
{
|
||||||
|
return (TraceEntry*)fEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
TraceEntry* Next()
|
||||||
|
{
|
||||||
|
if (fIndex == 0) {
|
||||||
|
fEntry = _NextNonBufferEntry(sFirstEntry);
|
||||||
|
fIndex = 1;
|
||||||
|
} else if (fEntry != NULL) {
|
||||||
|
fEntry = _NextNonBufferEntry(next_entry(fEntry));
|
||||||
|
fIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Current();
|
||||||
|
}
|
||||||
|
|
||||||
|
TraceEntry* Previous()
|
||||||
|
{
|
||||||
|
if (fIndex == (int32)sEntries + 1)
|
||||||
|
fEntry = sAfterLastEntry;
|
||||||
|
|
||||||
|
if (fEntry != NULL) {
|
||||||
|
fEntry = _PreviousNonBufferEntry(previous_entry(fEntry));
|
||||||
|
fIndex--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Current();
|
||||||
|
}
|
||||||
|
|
||||||
|
TraceEntry* MoveTo(int32 index)
|
||||||
|
{
|
||||||
|
if (index == fIndex)
|
||||||
|
return Current();
|
||||||
|
|
||||||
|
if (index <= 0 || index > (int32)sEntries) {
|
||||||
|
fIndex = (index <= 0 ? 0 : sEntries + 1);
|
||||||
|
fEntry = NULL;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the shortest iteration path
|
||||||
|
int32 distance = index - fIndex;
|
||||||
|
int32 direction = distance < 0 ? -1 : 1;
|
||||||
|
distance *= direction;
|
||||||
|
|
||||||
|
if (index < distance) {
|
||||||
|
distance = index;
|
||||||
|
direction = 1;
|
||||||
|
fEntry = NULL;
|
||||||
|
fIndex = 0;
|
||||||
|
}
|
||||||
|
if ((int32)sEntries + 1 - fIndex < distance) {
|
||||||
|
distance = sEntries + 1 - fIndex;
|
||||||
|
direction = -1;
|
||||||
|
fEntry = NULL;
|
||||||
|
fIndex = sEntries + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// iterate to the index
|
||||||
|
if (direction < 0) {
|
||||||
|
while (fIndex != index)
|
||||||
|
Previous();
|
||||||
|
} else {
|
||||||
|
while (fIndex != index)
|
||||||
|
Next();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Current();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
trace_entry* _NextNonBufferEntry(trace_entry* entry)
|
||||||
|
{
|
||||||
|
while (entry != NULL && (entry->flags & BUFFER_ENTRY) != 0)
|
||||||
|
entry = next_entry(entry);
|
||||||
|
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
trace_entry* _PreviousNonBufferEntry(trace_entry* entry)
|
||||||
|
{
|
||||||
|
while (entry != NULL && (entry->flags & BUFFER_ENTRY) != 0)
|
||||||
|
entry = previous_entry(entry);
|
||||||
|
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
trace_entry* fEntry;
|
||||||
|
int32 fIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
dump_tracing(int argc, char** argv)
|
dump_tracing(int argc, char** argv)
|
||||||
{
|
{
|
||||||
int argi = 1;
|
int argi = 1;
|
||||||
|
|
||||||
|
// variables in which we store our state to be continuable
|
||||||
|
static int32 _previousCount = 0;
|
||||||
|
static bool _previousHasFilter = false;
|
||||||
|
static int32 _previousMaxToCheck = 0;
|
||||||
|
static int32 _previousFirstChecked = 1;
|
||||||
|
static int32 _previousLastChecked = -1;
|
||||||
|
static uint32 _previousWritten = 0;
|
||||||
|
|
||||||
// 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, sEntries]).
|
||||||
int32 count = 30;
|
|
||||||
int32 start = 0; // special index: print the last count entries
|
int32 start = 0; // special index: print the last count entries
|
||||||
|
int32 count = 0;
|
||||||
|
int32 maxToCheck = 0;
|
||||||
int32 cont = 0;
|
int32 cont = 0;
|
||||||
|
|
||||||
bool hasFilter = false;
|
bool hasFilter = false;
|
||||||
@@ -506,33 +648,29 @@ dump_tracing(int argc, char** argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cont != 0 && argi < argc) {
|
if (cont != 0) {
|
||||||
print_debugger_command_usage(argv[0]);
|
if (argi < argc) {
|
||||||
return 0;
|
print_debugger_command_usage(argv[0]);
|
||||||
}
|
return 0;
|
||||||
|
}
|
||||||
// start
|
if (sWritten == 0 || sWritten != _previousWritten) {
|
||||||
if (argi < argc) {
|
kprintf("Can't continue iteration. \"%s\" has not been invoked "
|
||||||
if (strcmp(argv[argi], "filter") == 0) {
|
"before, or there were new entries written since the last "
|
||||||
hasFilter = true;
|
"invocation.\n", argv[0]);
|
||||||
argi++;
|
return 0;
|
||||||
} else if (argv[argi][0] == '#') {
|
|
||||||
hasFilter = true;
|
|
||||||
} else {
|
|
||||||
start = parse_expression(argv[argi]);
|
|
||||||
argi++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// count
|
// get start, count, maxToCheck
|
||||||
if (!hasFilter && argi < argc) {
|
int32* params[3] = { &start, &count, &maxToCheck };
|
||||||
|
for (int i = 0; i < 3 && !hasFilter && argi < argc; i++) {
|
||||||
if (strcmp(argv[argi], "filter") == 0) {
|
if (strcmp(argv[argi], "filter") == 0) {
|
||||||
hasFilter = true;
|
hasFilter = true;
|
||||||
argi++;
|
argi++;
|
||||||
} else if (argv[argi][0] == '#') {
|
} else if (argv[argi][0] == '#') {
|
||||||
hasFilter = true;
|
hasFilter = true;
|
||||||
} else {
|
} else {
|
||||||
count = parse_expression(argv[argi]);
|
*params[i] = parse_expression(argv[argi]);
|
||||||
argi++;
|
argi++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -549,56 +687,126 @@ dump_tracing(int argc, char** argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32 direction;
|
||||||
|
int32 firstToCheck;
|
||||||
|
int32 lastToCheck;
|
||||||
|
|
||||||
if (cont != 0) {
|
if (cont != 0) {
|
||||||
start = get_debug_variable("_tracingStart", start);
|
// get values from the previous iteration
|
||||||
count = get_debug_variable("_tracingCount", count);
|
direction = cont;
|
||||||
start = max_c(1, start + count * cont);
|
count = _previousCount;
|
||||||
hasFilter = get_debug_variable("_tracingFilter", count);
|
maxToCheck = _previousMaxToCheck;
|
||||||
|
hasFilter = _previousHasFilter;
|
||||||
|
|
||||||
|
if (direction < 0)
|
||||||
|
start = _previousFirstChecked - 1;
|
||||||
|
else
|
||||||
|
start = _previousLastChecked + 1;
|
||||||
|
} else {
|
||||||
|
// defaults for count and maxToCheck
|
||||||
|
if (count == 0)
|
||||||
|
count = 30;
|
||||||
|
if (maxToCheck == 0 || !hasFilter)
|
||||||
|
maxToCheck = count;
|
||||||
|
else if (maxToCheck < 0)
|
||||||
|
maxToCheck = sEntries;
|
||||||
|
|
||||||
|
// determine iteration direction
|
||||||
|
direction = (start <= 0 || count < 0 ? -1 : 1);
|
||||||
|
|
||||||
|
// validate count and maxToCheck
|
||||||
|
if (count < 0)
|
||||||
|
count = -count;
|
||||||
|
if (maxToCheck < 0)
|
||||||
|
maxToCheck = -maxToCheck;
|
||||||
|
if (maxToCheck > (int32)sEntries)
|
||||||
|
maxToCheck = sEntries;
|
||||||
|
if (count > maxToCheck)
|
||||||
|
count = maxToCheck;
|
||||||
|
|
||||||
|
// validate start
|
||||||
|
if (start <= 0 || start > (int32)sEntries)
|
||||||
|
start = max_c(1, sEntries);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((uint32)count > sEntries)
|
if (direction < 0) {
|
||||||
count = sEntries;
|
firstToCheck = max_c(1, start - maxToCheck + 1);
|
||||||
if (start <= 0)
|
lastToCheck = start;
|
||||||
start = max_c(1, sEntries - count + 1);
|
} else {
|
||||||
if (uint32(start + count) > sEntries)
|
firstToCheck = start;
|
||||||
count = sEntries - start + 1;
|
lastToCheck = min_c((int32)sEntries, start + maxToCheck - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TraceEntryIterator iterator(true);
|
||||||
|
|
||||||
|
char buffer[256];
|
||||||
|
LazyTraceOutput out(buffer, sizeof(buffer));
|
||||||
|
|
||||||
|
if (direction < 0 && hasFilter && lastToCheck - firstToCheck >= count) {
|
||||||
|
// iteration direction is backwards
|
||||||
|
|
||||||
|
// From the last entry to check iterate backwards to check filter
|
||||||
|
// matches.
|
||||||
|
int32 matching = 0;
|
||||||
|
|
||||||
|
// move to the entry after the last entry to check
|
||||||
|
iterator.MoveTo(lastToCheck + 1);
|
||||||
|
|
||||||
|
// iterate backwards
|
||||||
|
while (iterator.Index() > firstToCheck) {
|
||||||
|
TraceEntry* entry = iterator.Previous();
|
||||||
|
if ((entry->flags & ENTRY_INITIALIZED) != 0) {
|
||||||
|
out.Clear();
|
||||||
|
if (TraceFilterParser::Default()->Filter(entry, out)) {
|
||||||
|
matching++;
|
||||||
|
if (matching >= count)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
firstToCheck = iterator.Index();
|
||||||
|
|
||||||
|
// iterate to the previous entry, so that the next loop starts at the
|
||||||
|
// right one
|
||||||
|
iterator.Previous();
|
||||||
|
}
|
||||||
|
|
||||||
int32 index = 1;
|
|
||||||
int32 dumped = 0;
|
int32 dumped = 0;
|
||||||
|
|
||||||
for (trace_entry* current = sFirstEntry; current != NULL;
|
while (TraceEntry* entry = iterator.Next()) {
|
||||||
current = next_entry(current), index++) {
|
int32 index = iterator.Index();
|
||||||
if ((current->flags & BUFFER_ENTRY) != 0) {
|
if (index < firstToCheck)
|
||||||
// skip buffer entries
|
|
||||||
index--;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
if (index > lastToCheck || dumped >= count) {
|
||||||
if (index < start)
|
if (direction > 0)
|
||||||
continue;
|
lastToCheck = index - 1;
|
||||||
if (index >= start + count)
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if ((current->flags & ENTRY_INITIALIZED) != 0) {
|
if ((entry->flags & ENTRY_INITIALIZED) != 0) {
|
||||||
char buffer[256];
|
out.Clear();
|
||||||
LazyTraceOutput out(buffer, sizeof(buffer));
|
|
||||||
|
|
||||||
TraceEntry* entry = (TraceEntry*)current;
|
|
||||||
if (hasFilter && !TraceFilterParser::Default()->Filter(entry, out))
|
if (hasFilter && !TraceFilterParser::Default()->Filter(entry, out))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
kprintf("%5ld. %s\n", index, out.DumpEntry(entry));
|
kprintf("%5ld. %s\n", index, out.DumpEntry(entry));
|
||||||
} else
|
} else if (!hasFilter)
|
||||||
kprintf("%5ld. ** uninitialized entry **\n", index);
|
kprintf("%5ld. ** uninitialized entry **\n", index);
|
||||||
|
|
||||||
dumped++;
|
dumped++;
|
||||||
}
|
}
|
||||||
|
|
||||||
kprintf("entries %ld to %ld (%ld of %ld). %ld entries written\n", start,
|
kprintf("printed %ld entries within range %ld to %ld (%ld of %ld total, "
|
||||||
start + count - 1, dumped, sEntries, sWritten);
|
"%ld ever)\n", dumped, firstToCheck, lastToCheck,
|
||||||
|
lastToCheck - firstToCheck + 1, sEntries, sWritten);
|
||||||
|
|
||||||
set_debug_variable("_tracingStart", start);
|
// store iteration state
|
||||||
set_debug_variable("_tracingCount", count);
|
_previousCount = count;
|
||||||
set_debug_variable("_tracingFilter", hasFilter);
|
_previousMaxToCheck = maxToCheck;
|
||||||
|
_previousHasFilter = hasFilter;
|
||||||
|
_previousFirstChecked = firstToCheck;
|
||||||
|
_previousLastChecked = lastToCheck;
|
||||||
|
_previousWritten = sWritten;
|
||||||
|
|
||||||
return cont != 0 ? B_KDEBUG_CONT : 0;
|
return cont != 0 ? B_KDEBUG_CONT : 0;
|
||||||
}
|
}
|
||||||
@@ -691,18 +899,33 @@ tracing_init(void)
|
|||||||
|
|
||||||
add_debugger_command_etc("traced", &dump_tracing,
|
add_debugger_command_etc("traced", &dump_tracing,
|
||||||
"Dump recorded trace entries",
|
"Dump recorded trace entries",
|
||||||
"(\"forward\" | \"backward\") | ([ <start> [ <count> ] ] "
|
"(\"forward\" | \"backward\") | ([ <start> [ <count> [ <range> ] ] ] "
|
||||||
"[ #<pattern> | (\"filter\" <filter>) ])\n"
|
"[ #<pattern> | (\"filter\" <filter>) ])\n"
|
||||||
"Prints recorded trace entries. If \"backward\" or \"forward\" is\n"
|
"Prints recorded trace entries. If \"backward\" or \"forward\" is\n"
|
||||||
"specified, the command continues where the previous invocation left\n"
|
"specified, the command continues where the previous invocation left\n"
|
||||||
"off, i.e. printing the previous respectively next entries (as many\n"
|
"off, i.e. printing the previous respectively next entries (as many\n"
|
||||||
"as printed before). In this case the command is continuable, that is\n"
|
"as printed before). In this case the command is continuable, that is\n"
|
||||||
"afterwards entering an empty line in the debugger will reinvoke it.\n"
|
"afterwards entering an empty line in the debugger will reinvoke it.\n"
|
||||||
" <start> - The index of the first entry to print. The index of\n"
|
" <start> - The base index of the entries to print. Depending on\n"
|
||||||
" the first recorded entry is 1. If 0 is specified, the\n"
|
" whether the iteration direction is forward or\n"
|
||||||
" last <count> recorded entries are printed. Defaults \n"
|
" backward this will be the first or last entry printed\n"
|
||||||
|
" (potentially, if a filter is specified). The index of\n"
|
||||||
|
" the first entry in the trace buffer is 1. If 0 is\n"
|
||||||
|
" specified, the last <count> recorded entries are\n"
|
||||||
|
" printed (iteration direction is backward). Defaults \n"
|
||||||
" to 0.\n"
|
" to 0.\n"
|
||||||
" <count> - The number of entries to be printed. Defaults to 30.\n"
|
" <count> - The number of entries to be printed. Defaults to 30.\n"
|
||||||
|
" If negative, the -<count> entries before and\n"
|
||||||
|
" including <start> will be printed.\n"
|
||||||
|
" <range> - Only relevant if a filter is specified. Specifies the\n"
|
||||||
|
" number of entries to be filtered -- depending on the\n"
|
||||||
|
" iteration direction the entries before or after\n"
|
||||||
|
" <start>. If more than <count> entries match the\n"
|
||||||
|
" filter, only the first (forward) or last (backward)\n"
|
||||||
|
" <count> matching entries will be printed. If 0 is\n"
|
||||||
|
" specified <range> will be set to <count>. If -1,\n"
|
||||||
|
" <range> will be set to the number of recorded\n"
|
||||||
|
" entries.\n"
|
||||||
" <pattern> - If specified only entries containing this string are\n"
|
" <pattern> - If specified only entries containing this string are\n"
|
||||||
" printed.\n"
|
" printed.\n"
|
||||||
" <filter> - If specified only entries matching this filter\n"
|
" <filter> - If specified only entries matching this filter\n"
|
||||||
|
|||||||
Reference in New Issue
Block a user