static int cmd_grep(int argc, char** argv) { bool caseSensitive = true; bool inverseMatch = false; int argi = 1; for (; argi < argc; argi++) { const char* arg = argv[argi]; if (arg[0] != '-') break; for (int32 i = 1; arg[i] != '\0'; i++) { if (arg[i] == 'i') { caseSensitive = false; } else if (arg[i] == 'v') { inverseMatch = true; } else { print_debugger_command_usage(argv[0]); return B_KDEBUG_ERROR; } } } if (argc - argi != 2) { print_debugger_command_usage(argv[0]); return B_KDEBUG_ERROR; } const char* pattern = argv[argi++]; const char* line = argv[argi++]; bool match; if (caseSensitive) { match = strstr(line, pattern) != NULL; } else { match = false; int32 lineLen = strlen(line); int32 patternLen = strlen(pattern); for (int32 i = 0; i <= lineLen - patternLen; i++) { // This is rather slow, but should be OK for our purposes. if (strncasecmp(line + i, pattern, patternLen) == 0) { match = true; break; } } } if (match != inverseMatch) { kputs(line); kputs("\n"); } return 0; }
static int add_run_on_exit_command(int argc, char **argv) { if (argc < 2 || strcmp(argv[1], "--help") == 0) { print_debugger_command_usage(argv[0]); return 0; } if (argc > 256) { kprintf("too many arguments\n"); return 0; } size_t totalLength = 1; for (int32 i = 1; i < argc; i++) totalLength += strlen(argv[i]) + 1; if (sCommandOffset + totalLength > sizeof(sCommandBuffer)) { kprintf("no space left in command buffer\n"); return 0; } char *pointer = sCommandBuffer + sCommandOffset; *pointer++ = (char)(argc - 1); for (int32 i = 1; i < argc; i++) { strcpy(pointer, argv[i]); pointer += strlen(argv[i]) + 1; } sCommandOffset += totalLength; sCommandCount++; return 0; }
static int cmd_head(int argc, char** argv) { debugger_command_pipe_segment* segment = get_current_debugger_command_pipe_segment(); if (segment == NULL) { kprintf_unfiltered("%s can only be run as part of a pipe!\n", argv[0]); return B_KDEBUG_ERROR; } struct user_data { uint64 max_lines; uint64 lines; }; user_data* userData = (user_data*)segment->user_data; if (segment->invocations == 0) { if (argc != 3) { print_debugger_command_usage(argv[0]); return B_KDEBUG_ERROR; } if (!evaluate_debug_expression(argv[1], &userData->max_lines, false)) return B_KDEBUG_ERROR; userData->lines = 0; } if (++userData->lines <= userData->max_lines) { kputs(argv[2]); kputs("\n"); } return 0; }
static int dump_rw_lock_info(int argc, char** argv) { if (argc < 2) { print_debugger_command_usage(argv[0]); return 0; } rw_lock* lock = (rw_lock*)parse_expression(argv[1]); if (!IS_KERNEL_ADDRESS(lock)) { kprintf("invalid address: %p\n", lock); return 0; } kprintf("rw lock %p:\n", lock); kprintf(" name: %s\n", lock->name); kprintf(" holder: %" B_PRId32 "\n", lock->holder); kprintf(" count: %#" B_PRIx32 "\n", lock->count); kprintf(" active readers %d\n", lock->active_readers); kprintf(" pending readers %d\n", lock->pending_readers); kprintf(" owner count: %#" B_PRIx32 "\n", lock->owner_count); kprintf(" flags: %#" B_PRIx32 "\n", lock->flags); kprintf(" waiting threads:"); rw_lock_waiter* waiter = lock->waiters; while (waiter != NULL) { kprintf(" %" B_PRId32 "/%c", waiter->thread->id, waiter->writer ? 'w' : 'r'); waiter = waiter->next; } kputs("\n"); return 0; }
int dump_ici_message(int argc, char** argv) { if (argc != 2) { print_debugger_command_usage(argv[0]); return 0; } uint64 address; if (!evaluate_debug_expression(argv[1], &address, false)) return 0; smp_msg* message = (smp_msg*)(addr_t)address; kprintf("ICI message %p:\n", message); kprintf(" next: %p\n", message->next); kprintf(" message: %" B_PRId32 "\n", message->message); kprintf(" data: 0x%lx\n", message->data); kprintf(" data2: 0x%lx\n", message->data2); kprintf(" data3: 0x%lx\n", message->data3); kprintf(" data_ptr: %p\n", message->data_ptr); kprintf(" flags: %" B_PRIx32 "\n", message->flags); kprintf(" ref_count: %" B_PRIx32 "\n", message->ref_count); kprintf(" done: %s\n", message->done ? "true" : "false"); kprintf(" proc_bitmap: %" B_PRIx32 "\n", message->proc_bitmap); return 0; }
static int dump_mutex_info(int argc, char** argv) { if (argc < 2) { print_debugger_command_usage(argv[0]); return 0; } mutex* lock = (mutex*)parse_expression(argv[1]); if (!IS_KERNEL_ADDRESS(lock)) { kprintf("invalid address: %p\n", lock); return 0; } kprintf("mutex %p:\n", lock); kprintf(" name: %s\n", lock->name); kprintf(" flags: 0x%x\n", lock->flags); #if KDEBUG kprintf(" holder: %" B_PRId32 "\n", lock->holder); #else kprintf(" count: %" B_PRId32 "\n", lock->count); #endif kprintf(" waiting threads:"); mutex_waiter* waiter = lock->waiters; while (waiter != NULL) { kprintf(" %" B_PRId32, waiter->thread->id); waiter = waiter->next; } kputs("\n"); return 0; }
static int dump_io_request_owner(int argc, char** argv) { if (argc != 2) { print_debugger_command_usage(argv[0]); return 0; } IORequestOwner* owner = (IORequestOwner*)parse_expression(argv[1]); owner->Dump(); return 0; }
static int dump_io_scheduler(int argc, char** argv) { if (argc != 2) { print_debugger_command_usage(argv[0]); return 0; } IOScheduler* scheduler = (IOScheduler*)parse_expression(argv[1]); scheduler->Dump(); return 0; }
static int cmd_wc(int argc, char** argv) { debugger_command_pipe_segment* segment = get_current_debugger_command_pipe_segment(); if (segment == NULL) { kprintf_unfiltered("%s can only be run as part of a pipe!\n", argv[0]); return B_KDEBUG_ERROR; } struct user_data { uint64 lines; uint64 words; uint64 chars; }; user_data* userData = (user_data*)segment->user_data; if (segment->invocations == 0) { if (argc != 2) { print_debugger_command_usage(argv[0]); return B_KDEBUG_ERROR; } userData->lines = 0; userData->words = 0; userData->chars = 0; } const char* line = argv[1]; if (line == NULL) { // last run -- print results kprintf("%10" B_PRIu64 " %10" B_PRIu64 " %10" B_PRIu64 "\n", userData->lines, userData->words, userData->chars); return 0; } userData->lines++; userData->chars++; // newline // count words and chars in this line bool inWord = false; for (; *line != '\0'; line++) { userData->chars++; if ((isspace(*line) != 0) == inWord) { inWord = !inWord; if (inWord) userData->words++; } } return 0; }
static int cmd_error(int argc, char **argv) { if (argc != 2) { print_debugger_command_usage(argv[0]); return 0; } int32 error = parse_expression(argv[1]); kprintf("error 0x%" B_PRIx32 ": %s\n", error, strerror(error)); return 0; }
static int cmd_tail(int argc, char** argv) { debugger_command_pipe_segment* segment = get_current_debugger_command_pipe_segment(); if (segment == NULL) { kprintf_unfiltered("%s can only be run as part of a pipe!\n", argv[0]); return B_KDEBUG_ERROR; } struct user_data { uint64 max_lines; int64 line_count; bool restarted; }; user_data* userData = (user_data*)segment->user_data; if (segment->invocations == 0) { if (argc > 3) { print_debugger_command_usage(argv[0]); return B_KDEBUG_ERROR; } userData->max_lines = 10; if (argc > 2 && !evaluate_debug_expression(argv[1], &userData->max_lines, false)) { return B_KDEBUG_ERROR; } userData->line_count = 1; userData->restarted = false; } else if (!userData->restarted) { if (argv[argc - 1] == NULL) { userData->restarted = true; userData->line_count -= userData->max_lines; return B_KDEBUG_RESTART_PIPE; } ++userData->line_count; } else { if (argv[argc - 1] == NULL) return 0; if (--userData->line_count < 0) { kputs(argv[argc - 1]); kputs("\n"); } } return 0; }
static int cmd_faults(int argc, char** argv) { if (argc > 2) { print_debugger_command_usage(argv[0]); return B_KDEBUG_ERROR; } if (argc == 2) gInvokeCommandDirectly = parse_expression(argv[1]) == 0; kprintf("Fault handling is %s%s.\n", argc == 2 ? "now " : "", gInvokeCommandDirectly ? "off" : "on"); return 0; }
static int cmd_expr(int argc, char **argv) { if (argc != 2) { print_debugger_command_usage(argv[0]); return 0; } uint64 result; if (evaluate_debug_expression(argv[1], &result, false)) { kprintf("%" B_PRIu64 " (0x%" B_PRIx64 ")\n", result, result); set_debug_variable("_", result); } return 0; }
static int dump_port_info(int argc, char** argv) { ConditionVariable* condition = NULL; const char* name = NULL; if (argc < 2) { print_debugger_command_usage(argv[0]); return 0; } if (argc > 2) { if (!strcmp(argv[1], "address")) { _dump_port_info((struct port_entry*)parse_expression(argv[2])); return 0; } else if (!strcmp(argv[1], "condition")) condition = (ConditionVariable*)parse_expression(argv[2]); else if (!strcmp(argv[1], "name")) name = argv[2]; } else if (parse_expression(argv[1]) > 0) { // if the argument looks like a number, treat it as such int32 num = parse_expression(argv[1]); int32 slot = num % sMaxPorts; if (sPorts[slot].id != num) { kprintf("port %ld (%#lx) doesn't exist!\n", num, num); return 0; } _dump_port_info(&sPorts[slot]); return 0; } else name = argv[1]; // walk through the ports list, trying to match name for (int32 i = 0; i < sMaxPorts; i++) { if ((name != NULL && sPorts[i].lock.name != NULL && !strcmp(name, sPorts[i].lock.name)) || (condition != NULL && (&sPorts[i].read_condition == condition || &sPorts[i].write_condition == condition))) { _dump_port_info(&sPorts[i]); return 0; } } return 0; }
static int dump_sem_info(int argc, char **argv) { bool found = false; addr_t num; int32 i; if (argc < 2) { print_debugger_command_usage(argv[0]); return 0; } num = strtoul(argv[1], NULL, 0); if (IS_KERNEL_ADDRESS(num)) { dump_sem((struct sem_entry *)num); return 0; } else if (num >= 0) { uint32 slot = num % sMaxSems; if (sSems[slot].id != (int)num) { kprintf("sem %ld (%#lx) doesn't exist!\n", num, num); return 0; } dump_sem(&sSems[slot]); return 0; } // walk through the sem list, trying to match name for (i = 0; i < sMaxSems; i++) { if (sSems[i].u.used.name != NULL && strcmp(argv[1], sSems[i].u.used.name) == 0) { dump_sem(&sSems[i]); found = true; } } if (!found) kprintf("sem \"%s\" doesn't exist!\n", argv[1]); return 0; }
int dump_spinlock(int argc, char** argv) { if (argc != 2) { print_debugger_command_usage(argv[0]); return 0; } uint64 address; if (!evaluate_debug_expression(argv[1], &address, false)) return 0; spinlock* lock = (spinlock*)(addr_t)address; kprintf("spinlock %p:\n", lock); bool locked = B_SPINLOCK_IS_LOCKED(lock); if (locked) { kprintf(" locked from %p\n", find_lock_caller(lock)); } else kprintf(" not locked\n"); return 0; }
/*static*/ int Inode::Dump(int argc, char** argv) { bool dumpData = false; int argi = 1; if (argi < argc && strcmp(argv[argi], "-d") == 0) { dumpData = true; argi++; } if (argi >= argc || argi + 2 < argc) { print_debugger_command_usage(argv[0]); return 0; } Inode* node = (Inode*)parse_expression(argv[argi]); if (IS_USER_ADDRESS(node)) { kprintf("invalid FIFO address\n"); return 0; } node->Dump(dumpData); return 0; }
int dump_tracing_internal(int argc, char** argv, WrapperTraceFilter* wrapperFilter) { int argi = 1; // variables in which we store our state to be continuable static int32 _previousCount = 0; static bool _previousHasFilter = false; static bool _previousPrintStackTrace = false; static int32 _previousMaxToCheck = 0; static int32 _previousFirstChecked = 1; static int32 _previousLastChecked = -1; static int32 _previousDirection = 1; static uint32 _previousEntriesEver = 0; static uint32 _previousEntries = 0; static uint32 _previousOutputFlags = 0; static TraceEntryIterator iterator; uint32 entriesEver = sTracingMetaData->EntriesEver(); // Note: start and index are Pascal-like indices (i.e. in [1, Entries()]). int32 start = 0; // special index: print the last count entries int32 count = 0; int32 maxToCheck = 0; int32 cont = 0; bool hasFilter = false; bool printStackTrace = false; uint32 outputFlags = 0; while (argi < argc) { if (strcmp(argv[argi], "--difftime") == 0) { outputFlags |= TRACE_OUTPUT_DIFF_TIME; argi++; } else if (strcmp(argv[argi], "--printteam") == 0) { outputFlags |= TRACE_OUTPUT_TEAM_ID; argi++; } else if (strcmp(argv[argi], "--stacktrace") == 0) { printStackTrace = true; argi++; } else break; } if (argi < argc) { if (strcmp(argv[argi], "forward") == 0) { cont = 1; argi++; } else if (strcmp(argv[argi], "backward") == 0) { cont = -1; argi++; } } else cont = _previousDirection; if (cont != 0) { if (argi < argc) { print_debugger_command_usage(argv[0]); return 0; } if (entriesEver == 0 || entriesEver != _previousEntriesEver || sTracingMetaData->Entries() != _previousEntries) { kprintf("Can't continue iteration. \"%s\" has not been invoked " "before, or there were new entries written since the last " "invocation.\n", argv[0]); return 0; } } // get start, count, maxToCheck int32* params[3] = { &start, &count, &maxToCheck }; for (int i = 0; i < 3 && !hasFilter && argi < argc; i++) { if (strcmp(argv[argi], "filter") == 0) { hasFilter = true; argi++; } else if (argv[argi][0] == '#') { hasFilter = true; } else { *params[i] = parse_expression(argv[argi]); argi++; } } // filter specification if (argi < argc) { hasFilter = true; if (strcmp(argv[argi], "filter") == 0) argi++; if (!TraceFilterParser::Default()->Parse(argc - argi, argv + argi)) { print_debugger_command_usage(argv[0]); return 0; } } int32 direction; int32 firstToCheck; int32 lastToCheck; if (cont != 0) { // get values from the previous iteration direction = cont; count = _previousCount; maxToCheck = _previousMaxToCheck; hasFilter = _previousHasFilter; outputFlags = _previousOutputFlags; printStackTrace = _previousPrintStackTrace; 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 = sTracingMetaData->Entries(); // 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)sTracingMetaData->Entries()) maxToCheck = sTracingMetaData->Entries(); if (count > maxToCheck) count = maxToCheck; // validate start if (start <= 0 || start > (int32)sTracingMetaData->Entries()) start = max_c(1, sTracingMetaData->Entries()); } if (direction < 0) { firstToCheck = max_c(1, start - maxToCheck + 1); lastToCheck = start; } else { firstToCheck = start; lastToCheck = min_c((int32)sTracingMetaData->Entries(), start + maxToCheck - 1); } // reset the iterator, if something changed in the meantime if (entriesEver == 0 || entriesEver != _previousEntriesEver || sTracingMetaData->Entries() != _previousEntries) { iterator.Reset(); } LazyTraceOutput out(sTracingMetaData->TraceOutputBuffer(), kTraceOutputBufferSize, outputFlags); bool markedMatching = false; int32 firstToDump = firstToCheck; int32 lastToDump = lastToCheck; TraceFilter* filter = NULL; if (hasFilter) filter = TraceFilterParser::Default()->Filter(); if (wrapperFilter != NULL) { wrapperFilter->Init(filter, direction, cont != 0); filter = wrapperFilter; } if (direction < 0 && filter && lastToCheck - firstToCheck >= count) { // iteration direction is backwards markedMatching = true; // 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 firstToDump = -1; lastToDump = -1; while (iterator.Index() > firstToCheck) { TraceEntry* entry = iterator.Previous(); if ((entry->Flags() & ENTRY_INITIALIZED) != 0) { out.Clear(); if (filter->Filter(entry, out)) { entry->ToTraceEntry()->flags |= FILTER_MATCH; if (lastToDump == -1) lastToDump = iterator.Index(); firstToDump = iterator.Index(); matching++; if (matching >= count) break; } else entry->ToTraceEntry()->flags &= ~FILTER_MATCH; } } firstToCheck = iterator.Index(); // iterate to the previous entry, so that the next loop starts at the // right one iterator.Previous(); } out.SetLastEntryTime(0); // set the iterator to the entry before the first one to dump iterator.MoveTo(firstToDump - 1); // dump the entries matching the filter in the range // [firstToDump, lastToDump] int32 dumped = 0; while (TraceEntry* entry = iterator.Next()) { int32 index = iterator.Index(); if (index < firstToDump) continue; if (index > lastToDump || dumped >= count) { if (direction > 0) lastToCheck = index - 1; break; } if ((entry->Flags() & ENTRY_INITIALIZED) != 0) { out.Clear(); if (filter && (markedMatching ? (entry->Flags() & FILTER_MATCH) == 0 : !filter->Filter(entry, out))) { continue; } // don't print trailing new line const char* dump = out.DumpEntry(entry); int len = strlen(dump); if (len > 0 && dump[len - 1] == '\n') len--; kprintf("%5" B_PRId32 ". %.*s\n", index, len, dump); if (printStackTrace) { out.Clear(); entry->DumpStackTrace(out); if (out.Size() > 0) kputs(out.Buffer()); } } else if (!filter) kprintf("%5" B_PRId32 ". ** uninitialized entry **\n", index); dumped++; } kprintf("printed %" B_PRId32 " entries within range %" B_PRId32 " to %" B_PRId32 " (%" B_PRId32 " of %" B_PRId32 " total, %" B_PRId32 " ever)\n", dumped, firstToCheck, lastToCheck, lastToCheck - firstToCheck + 1, sTracingMetaData->Entries(), entriesEver); // store iteration state _previousCount = count; _previousMaxToCheck = maxToCheck; _previousHasFilter = hasFilter; _previousPrintStackTrace = printStackTrace; _previousFirstChecked = firstToCheck; _previousLastChecked = lastToCheck; _previousDirection = direction; _previousEntriesEver = entriesEver; _previousEntries = sTracingMetaData->Entries(); _previousOutputFlags = outputFlags; return cont != 0 ? B_KDEBUG_CONT : 0; }
int disasm_command(int argc, char **argv) { int argi = 1; // get back count uint64 backCount = 0; if (argi < argc && strcmp(argv[argi], "-b") == 0) { if (++argi >= argc) { print_debugger_command_usage(argv[0]); return 0; } if (!evaluate_debug_expression(argv[argi++], &backCount, false)) return 0; } if (argi + 2 < argc) { print_debugger_command_usage(argv[0]); return 0; } // get PC uint64 pc; if (argi < argc) { if (!evaluate_debug_expression(argv[argi++], &pc, false)) return 0; } else { pc = (addr_t)arch_debug_get_interrupt_pc(NULL); if (pc == 0) { kprintf("Failed to get current PC!\n"); return 0; } } // get count uint64 count = 10; if (argi < argc) { if (!evaluate_debug_expression(argv[argi++], &count, false)) return 0; } // TODO: autoincrement // if back count is given, compute base address addr_t baseAddress = 0; if (backCount > 0) { status_t error; const char *symbol; const char *imageName; bool exactMatch; if (IS_KERNEL_ADDRESS(pc)) { error = elf_debug_lookup_symbol_address(pc, &baseAddress, &symbol, &imageName, &exactMatch); } else { error = elf_debug_lookup_user_symbol_address( debug_get_debugged_thread()->team, pc, &baseAddress, &symbol, &imageName, &exactMatch); } if (error != B_OK) { baseAddress = 0; backCount = 0; } } disasm_arch_dump_insns((addr_t)pc, count, baseAddress, backCount); return 0; }