Coming from WinDbg

ntoseye uses the WinDbg command language, so most commands that you type in WinDbg work in ntoseye without changes. This page lists what works the same, what has a different syntax or is not available, and what only ntoseye has.

What carries over

  • Command names and syntax. bp, kn, dt, !process, lm, u, the d* and e* families, .reload, .sympath, !analyze, and many more commands have the same names and syntax. The command reference lists all of them.

  • MASM expressions. ntoseye uses MASM expressions with the WinDbg default radix (hexadecimal). This includes poi(), by/wo/dwo/qwo, @rax, $ip/$proc/$thread and the other pseudo-registers, @$name, and separated addresses such as fffff803`1a2b3c4d. See Expressions.

  • The breakpoint grammar. Breakpoints accept pass counts, if <expr> conditions, do "<commands>" actions that resume with g or gc, and /1, /p, and /t. See Breakpoints.

  • Command programs and scripts. ntoseye has .if/.elsif/.else, .while, .for, .do, .break, .continue, .block, j, .foreach, the !for_each_* commands, and $t0-$t19. You can run script files with $<, $$<, $><, $$><, and $$>a<, and scripts can use ${$arg1} and ${/d:$arg1}. As with cdb -c, -c '<commands>' runs commands at startup, and with --batch ntoseye quits after them; see Commands from the command line.

  • Address ranges. L<count>, L?<count>, L-<count>, and an end address work the same. The range includes the end address, so db nt nt+7 shows 8 bytes.

  • Symbols. The default symbol server is the Microsoft symbol server, and the cache under ~/.ntoseye/symbols uses the symstore layout, which WinDbg also reads.

  • .kdfiles. .kdfiles reads WinDbg driver replacement map files. See Driver replacement.

Spelled differently, or missing

In WinDbg

In ntoseye

dx queries, ??, @@c++( )

dx shows a typed expression and its fields, such as dx -r1 ((nt!_EPROCESS*)@rcx)->Pcb, the data model’s sessions, processes, threads, modules, and handles (@$curprocess, Debugger.Sessions[0].Processes[4], @$curprocess.Io.Handles), and queries with lambdas (.Where, .Select, .OrderBy, new { }, FromListEntry), but not GroupBy, aggregates such as Sum, functions of your own, or JavaScript. For ??, use dx or a typed expression with ev, such as ev @$proc->UniqueProcessId. Member access gives the value of the field, not its address. There is no C++ evaluator, so ntoseye does not scale pointer arithmetic. See dx and queries.

!name for a symbol in any module

Use module!name. In ntoseye, a leading ! negates the value, and !name alone shows a message that the name is ambiguous.

x exact wildcard match

x does a fuzzy search. * and ? are still wildcards, and ^, $, ', !, and spaces make the search narrower.

as Name Text with ${Name} substituted in later commands

as defines a command alias. For example, type as ubp bp ${1}; g, then type ubp nt!NtCreateFile. ${1}, ${2}, … and ${*} are the arguments of the alias.

.process /i (invasive switch, then g)

.process switches to the process immediately, with or without /i, because ntoseye reads the memory of any process through that process’s page tables. Without /i, the context lasts until the target runs, as in WinDbg. With /i it stays after the target runs, until the process exits, and it also selects a thread of the process, as WinDbg’s g ends in one: the thread a processor runs, else its first, by its stack. attach <pid> does the same as /i.

!wmitrace.searchpath, !wmitrace.tmffile (WPP message formatting)

You do not need these commands, and ntoseye does not read .tmf files. Instead, !wmitrace.logdump formats a WPP message from the trace message format (TMF) annotations in a loaded PDB that declares the message, and shows the raw message if no loaded PDB declares it. The public Microsoft Wdf01000.pdb contains the TMF for KMDF. For other drivers, the TMF is only in the driver’s private PDB, which you can add with .sympath+ (see Symbols and source).

.detach

Not available. q (also qd) removes the session’s breakpoints and exits, and the guest continues to run.

a (assemble), .fnret, !for_each_local

Not available. ntoseye does not assemble code, and public symbols do not contain return types or local types. To write bytes, use eb.

!wdfkd.* (KMDF)

ntoseye has !wdfkd.wdfldr, !wdfkd.wdfdriverinfo, !wdfkd.wdfhandle, !wdfkd.wdfobject, !wdfkd.wdfdevice, !wdfkd.wdfqueue, !wdfkd.wdfrequest, !wdfkd.wdfiotarget, !wdfkd.wdflogdump, and !wdfkd.wdfcrashdump, which use Wdf01000.pdb. The other !wdfkd commands and UMDF are not available. See KMDF drivers.

!storagekd.* (StorPort)

ntoseye has !storagekd.storadapter, !storagekd.storunit, !storagekd.storloglist, !storagekd.storlogirp, !storagekd.storlogsrb, !storagekd.storsrb, and !storagekd.storclass, which use storport.pdb and classpnp.pdb. The other !storagekd commands are not available. See StorPort adapters.

!ndiskd.* (NDIS)

ntoseye has !ndiskd.miniports, !ndiskd.miniport, !ndiskd.minidriver, !ndiskd.filter, !ndiskd.filterdriver, !ndiskd.protocol, !ndiskd.oid, and !ndiskd.nbl, which use ndis.pdb. The other !ndiskd commands, such as NetAdapterCx’s, are not available. See Network miniports.

!rcdrkd.* (WPP recorder)

ntoseye has !rcdrkd.rcdrloglist and !rcdrkd.rcdrlogdump, which format messages from the TMF annotations in loaded PDBs instead of .tmf files. See The WPP recorder.

!apic, !ioapic

!apic needs kd or kdnet and shows the APIC of the selected processor, or of the processor you give (!apic 2). !ioapic shows the I/O APIC lines as the HAL recorded them, from kernel memory, rather than reading the I/O APIC’s registers.

!sysinfo

!sysinfo takes machineid, smbios, and cpuinfo.

!reg

!reg has hivelist, querykey (q), keyinfo, and cellindex. querykey reads the hives themselves, so it shows any key, not only the keys that the kernel has cached, and -v <value> shows one value in full. The other !reg subcommands, such as kcb and openkeys, are not available. See The registry.

~ lists threads of a user-mode process

~ lists the processors (vCPUs), and ~Ns selects a processor. For Windows threads, use threads and !thread.

Behaves differently

  • Breakpoint scoping is a filter. ntoseye checks bp /p <pid> and /t when a breakpoint hits, but the breakpoint itself is global. A breakpoint in a shared DLL therefore stops every process that runs that code, and ntoseye resumes the hits outside the scope without showing a message. Breakpoints in shared pages explains the cost. WinDbg has no equivalent of /c <processor>, which limits a breakpoint to one processor.

  • !uniqstack groups kernel threads. In WinDbg, the user-mode !uniqstack groups the threads of one process. In ntoseye, it groups the threads of the .process process, or all threads in the system, and a stack includes the user frames below a system call.

  • .shell runs only at the interactive prompt. ntoseye does not accept .shell in breakpoint actions, exception commands, MCP, DAP, or the SDK, so a client cannot start programs on the host.

  • Some hardware access depends on the backend. Port I/O (ib, ob, and their word and dword forms) needs the kd or kdnet backend. !pci reads configuration space over kd, kdnet, or gdb, but cannot read it from memory alone. !pcitree works on all backends.

  • Some backends need no debugger in Windows. With the gdb and memory backends, Windows starts normally without bcdedit /debug, so it does not detect the debugger and operates as it does in production. See Choosing a backend.

Only in ntoseye