/* *kdb_lockprotectsupdatestokdb_initial_cpu.Usedto *singlethreadprocessorsthroughthekerneldebugger.
*/ int kdb_initial_cpu = -1; /* cpu number that owns kdb */ int kdb_nextline = 1; int kdb_state; /* General KDB state */
staticint kdb_check_regs(void)
{ if (!kdb_current_regs) {
kdb_printf("No current kdb registers." " You may need to select another task\n"); return KDB_BADREG;
} return0;
}
/* *kdbgetaddrarg-Thisfunctionisresponsibleforparsingan *address-expressionandreturningthevalueoftheexpression, *symbolname,andoffsettothecaller. * *Theargumentmayconsistofanumericvalue(decimalor *hexadecimal),asymbolname,aregistername(precededbythe *percentsign),anenvironmentvariablewithanumericvalue *(precededbyadollarsign)orasimplearithmeticexpression *consistingofasymbolname,+/-,andanumericconstantvalue *(offset). *Parameters: *argc-countofargumentsinargv *argv-argumentvector **nextarg-indextonextunparsedargumentinargv[] *regs-RegisterstateattimeofKDBentry *Outputs: **value-receivesthevalueoftheaddress-expression **offset-receivestheoffsetspecified,ifany **name-receivesthesymbolname,ifany **nextarg-indextonextunparsedargumentinargv[] *Returns: *zeroisreturnedonsuccess,akdbdiagnosticcodeis *returnedonerror.
*/ int kdbgetaddrarg(int argc, constchar **argv, int *nextarg, unsignedlong *value, long *offset, char **name)
{ unsignedlong addr; unsignedlong off = 0; int positive; int diag; int found = 0; char *symname; char symbol = '\0'; char *cp;
kdb_symtab_t symtab;
if (symname[0] == '$') {
diag = kdbgetulenv(&symname[1], &addr); if (diag) return diag;
} elseif (symname[0] == '%') {
diag = kdb_check_regs(); if (diag) return diag; /* Implement register values with % at a later time as it is *archoptional.
*/ return KDB_NOTIMP;
} else {
found = kdbgetsymval(symname, &symtab); if (found) {
addr = symtab.sym_start;
} else {
diag = kdbgetularg(argv[*nextarg], &addr); if (diag) return diag;
}
}
if (!found)
found = kdbnearsym(addr, &symtab);
(*nextarg)++;
if (name)
*name = symname; if (value)
*value = addr; if (offset && name && *name)
*offset = addr - symtab.sym_start;
if ((*nextarg > argc)
&& (symbol == '\0')) return0;
/* sanity check: we should have been called with the \ first */ if (*cp != '|') return;
cp++; while (isspace(*cp))
cp++; if (!str_has_prefix(cp, "grep ")) {
kdb_printf("invalid 'pipe', see grephelp\n"); return;
}
cp += 5; while (isspace(*cp))
cp++;
cp2 = strchr(cp, '\n'); if (cp2)
*cp2 = '\0'; /* remove the trailing newline */
len = strlen(cp); if (len == 0) {
kdb_printf("invalid 'pipe', see grephelp\n"); return;
} /* now cp points to a nonzero length search string */ if (*cp == '"') { /* allow it be "x y z" by removing the "'s - there must
be two of them */
cp++;
cp2 = strchr(cp, '"'); if (!cp2) {
kdb_printf("invalid quoted string, see grephelp\n"); return;
}
*cp2 = '\0'; /* end the string where the 2nd " was */
}
kdb_grep_leading = 0; if (*cp == '^') {
kdb_grep_leading = 1;
cp++;
}
len = strlen(cp);
kdb_grep_trailing = 0; if (*(cp+len-1) == '$') {
kdb_grep_trailing = 1;
*(cp+len-1) = '\0';
}
len = strlen(cp); if (!len) return; if (len >= KDB_GREP_STRLEN) {
kdb_printf("search string too long\n"); return;
}
strcpy(kdb_grep_string, cp);
kdb_grepping_flag++; return;
}
if (KDB_FLAG(CMD_INTERRUPT)) { /* Previous command was interrupted, newline must not
* repeat the command */
KDB_FLAG_CLEAR(CMD_INTERRUPT);
KDB_STATE_SET(PAGER);
argc = 0; /* no repeat */
}
if (*cp != '\n' && *cp != '\0') {
argc = 0;
cpp = cbuf; while (*cp) { /* skip whitespace */ while (isspace(*cp))
cp++; if ((*cp == '\0') || (*cp == '\n') ||
(*cp == '#' && !defcmd_in_progress)) break; /* special case: check for | grep pattern */ if (*cp == '|') {
check_grep++; break;
} if (cpp >= cbuf + CMD_BUFLEN) {
kdb_printf("kdb_parse: command buffer " "overflow, command ignored\n%s\n",
cmdstr); return KDB_NOTFOUND;
} if (argc >= MAXARGC - 1) {
kdb_printf("kdb_parse: too many arguments, " "command ignored\n%s\n", cmdstr); return KDB_NOTFOUND;
}
argv[argc++] = cpp;
escaped = 0;
quoted = '\0'; /* Copy to next unquoted and unescaped
* whitespace or '=' */ while (*cp && *cp != '\n' &&
(escaped || quoted || !isspace(*cp))) { if (cpp >= cbuf + CMD_BUFLEN) break; if (escaped) {
escaped = 0;
*cpp++ = *cp++; continue;
} if (*cp == '\\') {
escaped = 1;
++cp; continue;
} if (*cp == quoted)
quoted = '\0'; elseif (*cp == '\'' || *cp == '"')
quoted = *cp;
*cpp = *cp++; if (*cpp == '=' && !quoted) break;
++cpp;
}
*cpp++ = '\0'; /* Squash a ws or '=' character */
}
} if (!argc) return0; if (check_grep)
parse_grep(cp); if (defcmd_in_progress) { int result = kdb_defcmd2(cmdstr, argv[0]); if (!defcmd_in_progress) {
argc = 0; /* avoid repeat on endefcmd */
*(argv[0]) = '\0';
} return result;
} if (argv[0][0] == '-' && argv[0][1] &&
(argv[0][1] < '0' || argv[0][1] > '9')) {
ignore_errors = 1;
++argv[0];
}
if (!list_entry_is_head(tp, &kdb_cmds_head, list_node)) { int result;
if (!kdb_check_flags(tp->flags, kdb_cmd_enabled, argc <= 1)) return KDB_NOPERM;
KDB_STATE_SET(CMD);
result = (*tp->func)(argc-1, (constchar **)argv); if (result && ignore_errors && result > KDB_CMD_GO)
result = 0;
KDB_STATE_CLEAR(CMD);
if (tp->flags & KDB_REPEAT_WITH_ARGS) return result;
switch (reason) { case KDB_REASON_DEBUG:
{ /* *Ifre-enteringkdbafterasinglestep *command,don'tprintthemessage.
*/ switch (db_result) { case KDB_DB_BPT:
kdb_printf("\nEntering kdb (0x%px, pid %d) ",
kdb_current, kdb_current->pid); #ifdefined(CONFIG_SMP)
kdb_printf("on processor %d ", raw_smp_processor_id()); #endif
kdb_printf("due to Debug @ " kdb_machreg_fmt "\n",
instruction_pointer(regs)); break; case KDB_DB_SS: break; case KDB_DB_SSBPT:
KDB_DEBUG_STATE("kdb_local 4", reason); return1; /* kdba_db_trap did the work */ default:
kdb_printf("kdb: Bad result from kdba_db_trap: %d\n",
db_result); break;
}
} break; case KDB_REASON_ENTER: if (KDB_STATE(KEYBOARD))
kdb_printf("due to Keyboard Entry\n"); else
kdb_printf("due to KDB_ENTER()\n"); break; case KDB_REASON_KEYBOARD:
KDB_STATE_SET(KEYBOARD);
kdb_printf("due to Keyboard Entry\n"); break; case KDB_REASON_ENTER_SLAVE: /* drop through, slaves only get released via cpu switch */ case KDB_REASON_SWITCH:
kdb_printf("due to cpu switch\n"); break; case KDB_REASON_OOPS:
kdb_printf("Oops: %s\n", kdb_diemsg);
kdb_printf("due to oops @ " kdb_machreg_fmt "\n",
instruction_pointer(regs));
kdb_dumpregs(regs); break; case KDB_REASON_SYSTEM_NMI:
kdb_printf("due to System NonMaskable Interrupt\n"); break; case KDB_REASON_NMI:
kdb_printf("due to NonMaskable Interrupt @ "
kdb_machreg_fmt "\n",
instruction_pointer(regs)); break; case KDB_REASON_SSTEP: case KDB_REASON_BREAK:
kdb_printf("due to %s @ " kdb_machreg_fmt "\n",
reason == KDB_REASON_BREAK ? "Breakpoint" : "SS trap", instruction_pointer(regs)); /* *Determineifthisbreakpointisonethatwe *areinterestedin.
*/ if (db_result != KDB_DB_BPT) {
kdb_printf("kdb: error return from kdba_bp_trap: %d\n",
db_result);
KDB_DEBUG_STATE("kdb_local 6", reason); return0; /* Not for us, dismiss it */
} break; case KDB_REASON_RECURSE:
kdb_printf("due to Recursion @ " kdb_machreg_fmt "\n",
instruction_pointer(regs)); break; default:
kdb_printf("kdb: unexpected reason code: %d\n", reason);
KDB_DEBUG_STATE("kdb_local 8", reason); return0; /* Not for us, dismiss it */
}
while (1) { /* *Initializepagercontext.
*/
kdb_nextline = 1;
KDB_STATE_CLEAR(SUPPRESS);
kdb_grepping_flag = 0; /* ensure the old search does not leak into '/' commands */
kdb_grep_string[0] = '\0';
do_full_getstr: /* PROMPT can only be set if we have MEM_READ permission. */
snprintf(kdb_prompt_str, CMD_BUFLEN, kdbgetenv("PROMPT"),
raw_smp_processor_id());
if (diag)
kdb_cmderror(diag);
}
KDB_DEBUG_STATE("kdb_local 9", diag); return diag;
}
/* *kdb_print_state-Printthestatedataforthecurrentprocessor *fordebugging. *Inputs: *textIdentifiesthedebugpoint *valueAnyintegervaluetobeprinted,e.g.reasoncode.
*/ void kdb_print_state(constchar *text, int value)
{
kdb_printf("state: %s cpu %d value %d initial %d state %x\n",
text, raw_smp_processor_id(), value, kdb_initial_cpu,
kdb_state);
}
/* *kdb_main_loop-Afterinitialsetupandassignmentofthe *controllingcpu,allcpusareinthisloop.Onecpuisin *controlandwillissuethekdbprompt,theotherswillspin *until'go'orcpuswitch. * *Togetaconsistentviewofthekernelstacksforall *processes,thisroutineisinvokedfromthemainkdbcodevia *anarchitecturespecificroutine.kdba_main_loopis *responsibleformakingthekernelstacksconsistentforall *processes,thereshouldbenodifferencebetweenablocked *processandarunningprocessasfaraskdbisconcerned. *Inputs: *reasonThereasonKDBwasinvoked *errorThehardware-definederrorcode *reason2kdb'scurrentreasoncode. *Initiallyerrorbutcanchange *accordingtokdbstate. *db_resultResultcodefrombreakordebugpoint. *regsTheexceptionframeattimeoffault/breakpoint. *shouldalwaysbevalid. *Returns: *0KDBwasinvokedforaneventwhichitwasn'tresponsible *1KDBhandledtheeventforwhichitwasinvoked.
*/ int kdb_main_loop(kdb_reason_t reason, kdb_reason_t reason2, int error,
kdb_dbtrap_t db_result, struct pt_regs *regs)
{ int result = 1; /* Stay in kdb() until 'go', 'ss[b]' or an error */ while (1) { /* *Allprocessorsexcepttheonethatisincontrol *willspinhere.
*/
KDB_DEBUG_STATE("kdb_main_loop 1", reason); while (KDB_STATE(HOLD_CPU)) { /* state KDB is turned off by kdb_cpu to see if the *othercpusarestilllive,eachcpuinthisloop *turnsitbackon.
*/ if (!KDB_STATE(KDB))
KDB_STATE_SET(KDB);
}
KDB_STATE_CLEAR(SUPPRESS);
KDB_DEBUG_STATE("kdb_main_loop 2", reason); if (KDB_STATE(LEAVING)) break; /* Another cpu said 'go' */ /* Still using kdb, this processor is in control */
result = kdb_local(reason2, error, regs, db_result);
KDB_DEBUG_STATE("kdb_main_loop 3", result);
if (result == KDB_CMD_CPU) break;
if (result == KDB_CMD_SS) {
KDB_STATE_SET(DOING_SS); break;
}
if (result == KDB_CMD_KGDB) { if (!KDB_STATE(DOING_KGDB))
kdb_printf("Entering please attach debugger " "or use $D#44+ or $3#33\n"); break;
} if (result && result != 1 && result != KDB_CMD_GO)
kdb_printf("\nUnexpected kdb_local return code %d\n",
result);
KDB_DEBUG_STATE("kdb_main_loop 4", reason); break;
} if (KDB_STATE(DOING_SS))
KDB_STATE_CLEAR(SSBPT);
/* Clean up any keyboard devices before leaving */
kdb_kbd_cleanup_state();
/* *kdb_md-Thisfunctionimplementsthe'md','md1','md2','md4', *'md8''mdr'and'mds'commands. * *md|mds[<addrarg>[<linecount>[<radix>]]] *mdWcN[<addrarg>[<linecount>[<radix>]]] *whereW=isthewidth(1,2,4or8)andNisthecount. *foreg.,md1c20reads20bytes,1atatime. *mdr<addrarg>,<bytecount>
*/ staticvoid kdb_md_line(constchar *fmtstr, unsignedlong addr, int symbolic, int nosect, int bytesperword, int num, int repeat, int phys)
{ /* print just one line of data */
kdb_symtab_t symtab; char cbuf[32]; char *c = cbuf; int i; int j; unsignedlong word;
if (strcmp(argv[0], "mds") == 0) {
symbolic = 1; /* Do not save these changes as last_*, they are temporary mds *overrides.
*/
bytesperword = KDB_WORD_SIZE;
repeat = mdcount;
kdbgetintenv("NOSECT", &nosect);
}
/* Round address down modulo BYTESPERWORD */
addr &= ~(bytesperword-1);
while (repeat > 0) { unsignedlong a; int n, z, num = (symbolic ? 1 : (16 / bytesperword));
if (KDB_FLAG(CMD_INTERRUPT)) return0; for (a = addr, z = 0; z < repeat; a += bytesperword, ++z) { if (phys) { if (kdb_getphysword(&word, a, bytesperword)
|| word) break;
} elseif (kdb_getword(&word, a, bytesperword) || word) break;
}
n = min(num, repeat);
kdb_md_line(fmtstr, addr, symbolic, nosect, bytesperword,
num, repeat, phys);
addr += bytesperword * n;
repeat -= n;
z = (z + num - 1) / num; if (z > 2) { int s = num * (z-2);
kdb_printf(kdb_machreg_fmt0 "-" kdb_machreg_fmt0 " zero suppressed\n",
addr, addr + bytesperword * s - 1);
addr += bytesperword * s;
repeat -= s;
}
}
last_addr = addr;
return0;
}
/* *kdb_mm-Thisfunctionimplementsthe'mm'command. *mmaddress-expressionnew-value *Remarks: *mmworksonmachinewords,mmWworksonbytes.
*/ staticint kdb_mm(int argc, constchar **argv)
{ int diag; unsignedlong addr; long offset = 0; unsignedlong contents; int nextarg; int width;
if (argv[0][2] && !isdigit(argv[0][2])) return KDB_NOTFOUND;
if (KDB_DEBUG(MASK))
kdb_printf("KDBDEBUG=0x%x\n",
(kdb_flags & KDB_DEBUG(MASK)) >> KDB_DEBUG_FLAG_SHIFT);
return0;
}
#ifdef CONFIG_PRINTK /* *kdb_dmesg-Thisfunctionimplementsthe'dmesg'commandtodisplay *thecontentsofthesyslogbuffer. *dmesg[lines][adjust]
*/ staticint kdb_dmesg(int argc, constchar **argv)
{ int diag; int logging; int lines = 0; int adjust = 0; int n = 0; int skip = 0; struct kmsg_dump_iter iter;
size_t len; char buf[201];
if (argc > 2) return KDB_ARGCOUNT; if (argc) { if (kstrtoint(argv[1], 0, &lines))
lines = 0; if (argc > 1 && (kstrtoint(argv[2], 0, &adjust) || adjust < 0))
adjust = 0;
}
/* disable LOGGING if set */
diag = kdbgetintenv("LOGGING", &logging); if (!diag && logging) { constchar *setargs[] = { "set", "LOGGING", "0" };
kdb_set(2, setargs);
}
kmsg_dump_rewind(&iter); while (kmsg_dump_get_line(&iter, 1, NULL, 0, NULL))
n++;
if (lines < 0) { if (adjust >= n)
kdb_printf("buffer only contains %d lines, nothing " "printed\n", n); elseif (adjust - lines >= n)
kdb_printf("buffer only contains %d lines, last %d " "lines printed\n", n, n - adjust);
skip = adjust;
lines = abs(lines);
} elseif (lines > 0) {
skip = n - lines - adjust;
lines = abs(lines); if (adjust >= n) {
kdb_printf("buffer only contains %d lines, " "nothing printed\n", n);
skip = n;
} elseif (skip < 0) {
lines += skip;
skip = 0;
kdb_printf("buffer only contains %d lines, first " "%d lines printed\n", n, lines);
}
} else {
lines = n;
}
if (skip >= n || skip < 0) return0;
kmsg_dump_rewind(&iter); while (kmsg_dump_get_line(&iter, 1, buf, sizeof(buf), &len)) { if (skip) {
skip--; continue;
} if (!lines--) break; if (KDB_FLAG(CMD_INTERRUPT)) return0;
kdb_printf("Currently on cpu %d\n", raw_smp_processor_id());
kdb_printf("Available cpus: "); for (start_cpu = -1, i = 0; i < NR_CPUS; i++) { if (!cpu_online(i)) {
state = 'F'; /* cpu is offline */
} elseif (!kgdb_info[i].enter_kgdb) {
state = 'D'; /* cpu is online but unresponsive */
} else {
state = ' '; /* cpu is responding to kdb */ if (kdb_task_state_char(KDB_TSK(i)) == '-')
state = '-'; /* idle task */
} if (state != prev_state) { if (prev_state != '?') { if (!first_print)
kdb_printf(", ");
first_print = 0;
kdb_printf("%d", start_cpu); if (start_cpu < i-1)
kdb_printf("-%d", i-1); if (prev_state != ' ')
kdb_printf("(%c)", prev_state);
}
prev_state = state;
start_cpu = i;
}
} /* print the trailing cpus, ignoring them if they are all offline */ if (prev_state != 'F') { if (!first_print)
kdb_printf(", ");
kdb_printf("%d", start_cpu); if (start_cpu < i-1)
kdb_printf("-%d", i-1); if (prev_state != ' ')
kdb_printf("(%c)", prev_state);
}
kdb_printf("\n");
}
staticint kdb_cpu(int argc, constchar **argv)
{ unsignedlong cpunum; int diag;
if (argc == 0) {
kdb_cpu_status(); return0;
}
if (argc != 1) return KDB_ARGCOUNT;
diag = kdbgetularg(argv[1], &cpunum); if (diag) return diag;
/* The user may not realize that ps/bta with no parameters does not print idle *orsleepingsystemdaemonprocesses,sotellthemhowmanyweresuppressed.
*/ void kdb_ps_suppressed(void)
{ int idle = 0, daemon = 0; unsignedlong cpu; conststruct task_struct *p, *g;
for_each_online_cpu(cpu) {
p = curr_task(cpu); if (kdb_task_state(p, "-"))
++idle;
}
for_each_process_thread(g, p) { if (kdb_task_state(p, "ims"))
++daemon;
} if (idle || daemon) { if (idle)
kdb_printf("%d idle process%s (state -)%s\n",
idle, idle == 1 ? "" : "es",
daemon ? " and " : ""); if (daemon)
kdb_printf("%d sleeping system daemon (state [ims]) " "process%s", daemon,
daemon == 1 ? "" : "es");
kdb_printf(" suppressed,\nuse 'ps A' to see all.\n");
}
}
void kdb_ps1(conststruct task_struct *p)
{ int cpu; unsignedlong tmp;
if (!p ||
copy_from_kernel_nofault(&tmp, (char *)p, sizeof(unsignedlong))) return;
cpu = kdb_process_cpu(p);
kdb_printf("0x%px %8d %8d %d %4d %c 0x%px %c%s\n",
(void *)p, p->pid, p->parent->pid,
kdb_task_has_cpu(p), kdb_process_cpu(p),
kdb_task_state_char(p),
(void *)(&p->thread),
p == curr_task(raw_smp_processor_id()) ? '*' : ' ',
p->comm); if (kdb_task_has_cpu(p)) { if (!KDB_TSK(cpu)) {
kdb_printf(" Error: no saved data for this cpu\n");
} else { if (KDB_TSK(cpu) != p)
kdb_printf(" Error: does not match running " "process table (0x%px)\n", KDB_TSK(cpu));
}
}
}
if (argc == 0)
kdb_ps_suppressed();
kdb_printf("%-*s Pid Parent [*] cpu State %-*s Command\n",
(int)(2*sizeof(void *))+2, "Task Addr",
(int)(2*sizeof(void *))+2, "Thread");
mask = argc ? argv[1] : kdbgetenv("PS"); /* Run the active tasks first */
for_each_online_cpu(cpu) { if (KDB_FLAG(CMD_INTERRUPT)) return0;
p = curr_task(cpu); if (kdb_task_state(p, mask))
kdb_ps1(p);
}
kdb_printf("\n"); /* Now the real tasks */
for_each_process_thread(g, p) { if (KDB_FLAG(CMD_INTERRUPT)) return0; if (kdb_task_state(p, mask))
kdb_ps1(p);
}
if (argc) { if (strcmp(argv[1], "R") == 0) {
p = KDB_TSK(kdb_initial_cpu);
} else {
diag = kdbgetularg(argv[1], &val); if (diag) return KDB_BADINT;
p = find_task_by_pid_ns((pid_t)val, &init_pid_ns); if (!p) {
kdb_printf("No task with pid=%d\n", (pid_t)val); return0;
}
}
kdb_set_current_task(p);
}
kdb_printf("KDB current process is %s(pid=%d)\n",
kdb_current_task->comm,
kdb_current_task->pid);
/* *displayhelpfortheuseofcmd|greppattern
*/ staticint kdb_grep_help(int argc, constchar **argv)
{
kdb_printf("Usage of cmd args | grep pattern:\n");
kdb_printf(" Any command's output may be filtered through an ");
kdb_printf("emulated 'pipe'.\n");
kdb_printf(" 'grep' is just a key word.\n");
kdb_printf(" The pattern may include a very limited set of " "metacharacters:\n");
kdb_printf(" pattern or ^pattern or pattern$ or ^pattern$\n");
kdb_printf(" And if there are spaces in the pattern, you may " "quote it:\n");
kdb_printf(" \"pat tern\" or \"^pat tern\" or \"pat tern$\"" " or \"^pat tern$\"\n"); return0;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.