Symbols, types, and expressions

.fetchimage

Download the PE file of a loaded module into the symbol cache, or copy a file into it, and print its path.

.fetchimage <module>
.fetchimage /f <file>

The command finds the file by the TimeDateStamp and SizeOfImage values in the mapped PE header of the module. These values are the symbol-server key, so the file is the same build that is running, and a disassembler database that you make from this file rebases onto the live module. A copy in a local directory on the symbol path, at its root or in symbol-store layout, is used before a symbol server. /f copies a PE file that you have into the cache under the key in its own header, with the name of its PDB, so ntoseye finds it for the module that runs that build. Use it for the Windows hypervisor, which Microsoft’s symbol server does not have: copy C:\Windows\System32\hvix64.exe from the guest and run .fetchimage /f hvix64.exe, after which the stacks of a vCPU in the hypervisor unwind through the file’s unwind data.

.formats

Show an expression in common numeric formats.

.formats <expression>
.reload

Reload symbols for the modules in the current scope, or for the modules a name or pattern names.

.reload [/f] [/v] [/n|/user] [module]

Asks the symbol path again for each module’s PDB, whatever failed before, and loads it at once. The current scope’s modules are the selected process’s user-mode modules, else the kernel’s; /n reloads the kernel’s and /user the selected process’s. A module is a name such as nt or viostor.sys, or a pattern with * and ? such as vio*. /f and /v are accepted as in WinDbg: ntoseye always loads at once, and lm shows each module’s symbol status.

.srcpath

Show or replace the ordered local source path mappings.

.srcpath [local-root|recorded-prefix=local-root]...

A local root contains the source tree, and a recorded path such as C:\Users\me\repos\MyDriver\src\queue.c maps to a file under the root. ntoseye uses the longest trailing part of the recorded path that names a file under the root, so root/src/queue.c comes before root/queue.c. It tries an exact match first, and then a match that ignores case. A recorded-prefix=local-root mapping replaces the recorded prefix with the local root. If the PDB records the checksum of a source file, ntoseye shows only a file with that checksum, and reports a file with a different checksum as not the compiled source.

.srcpath+

Add local source path mappings to the end of the list.

.srcpath+ <local-root|recorded-prefix=local-root>...

ntoseye tries the mappings in order, as .srcpath describes.

.symfix

Set the symbol source path back to the defaults, the ntoseye cache and the Microsoft symbol server.

.symfix
.sympath

Show or replace the ordered symbol source path.

.sympath [directory|http-server]...
.sympath+

Add entries to the end of the ordered symbol source path.

.sympath+ <directory|http-server>...
?

Evaluate an expression.

? <expression>

Also: ev

Memory read functions and their sizes in bytes: by() 1, wo() 2, dwo() 4, qwo()/poi() 8. &expr gives the address of expr. -> and . give field values.

display

Show an expression’s value at every stop.

display [expression]

Each stop then ends with the display’s value, marked when it changed since the last stop. The expression keeps the radix it was entered in. Without an expression, display lists the displays with their values now. undisplay removes them.

dt

Show a type layout or a decoded structure.

dt [-r[N]] [-a[N]] [-v] [-y] [-l <field>] [module!]<type> [field-pattern]... [address] [field-pattern]...

-r expands nested structures, and -v shows field sizes. Arrays show their first 16 elements; -a shows the first N, up to 16. -y matches names by case-insensitive prefix, and -l walks a LIST_ENTRY field. ntoseye looks for a bare type name in the kernel PDB first, and then in the modules of the current address space. If the PDB of a module defines a member type, ntoseye names the type with that module (wdf01000!_WDF_DRIVER_GLOBALS) and expands it from that PDB. If the PDB only declares the type (a driver’s _EPROCESS*), ntoseye resolves it as a bare name. Nested field paths use dots, and field patterns support * and ?. A word that names a field of the type is a field pattern, so the address may come before or after the fields, as in WinDbg. With -l, the given address is the first element, as in WinDbg, so the walk includes all nodes until it returns to that address. In memory, a list head and a record link look the same, so if you start at a list head instead of at poi(ListHead), the command shows the head as one pseudo-record and does not drop a real record. If the list is empty, its link points to itself, and the command shows nothing. The walk keeps the entries that it collected, and reports null links, cycles, unreadable links, and when it reaches the entry limit.

dv

Show the locals and parameters of the selected frame.

dv [address]

Each frame shows only its own variables. For an inline frame, these are the variables of the inlined function, and the frame that contains the inlined call shows the variables of its procedure but not those of the calls that are inlined into it. Without an address, the command uses the frame that .frame selected or, if no frame is selected, the innermost frame at the stop. With an address, it uses the innermost frame at that address.

dx

Show a typed expression’s value and its fields.

dx [-r<depth>] [-g] [-v|-nv] <expression>[,d|,x|,<count>]

Evaluates an expression with casts, ->, ., [] and , such as dx -r1 (((nt!_IO_STACK_LOCATION )0xffff…)) or dx ((nt!_EPROCESS)@rcx)->UniqueProcessId, and shows its value with its type, then its fields -r levels deep (1 by default, -r0 for the value alone), following a pointer to a structure to the structure. Types read as in WinDbg (unsigned long, _EPROCESS *), and a cast takes them as WinDbg writes them, such as (unsigned long *). A pointer to a number shows the number it points to, a char or wchar_t pointer its string, and a function pointer the function. Numbers are decimal unless written with 0x, as in C++. @$proc, @$thread, @$teb and @$peb are typed pointers. The debugger data model’s objects read as in WinDbg: Debugger.Sessions, @$cursession, @$curprocess, and @$curthread, a session’s Processes (indexed by process ID), a process’s Name, Id, Threads (indexed by thread ID), Modules (indexed from 0), and Io.Handles (indexed by handle, each with its Type and Object), a thread’s Id, and a module’s BaseAddress, Name, and Size. KernelObject is the typed _EPROCESS or _ETHREAD, which reads on as a typed expression: dx @$curprocess.KernelObject.Pcb. A collection takes .Count() and the queries Where, Select, SelectMany, First, Last, Any, All, OrderBy, OrderByDescending, Take, and Skip with lambdas, as in dx @$cursession.Processes.Where(p => p.Name.Contains(“svchost”)).Select(p => new { Name = p.Name, Id = p.Id }), and Debugger.Utility.Collections.FromListEntry(head, “nt!_EPROCESS”, “ActiveProcessLinks”) walks a kernel list. -g shows a collection as a grid, and a format after the expression lists more elements than 100 (, 500) or shows the model’s numbers in decimal (, d). NatVis views (such as a driver object’s) are not supported. -nv is accepted as in WinDbg.

ln

List the symbol nearest to an address.

ln <address>
ls

List source lines of the file for the current scope.

ls [.] [first][,count]

With no arguments, the command continues after the lines that the previous ls or lsa showed, and . starts again at the current line. first is a line number, and count is 10 by default. The file is the file of the source line of the selected frame, which for an inline frame is in the inlined function. ntoseye finds the file through .srcpath.

lsa

List source lines around an address.

lsa [address][,first][,count]

By default, the command uses the source line of the selected frame, and shows twelve lines in total, starting five lines before that line. If you give an address, the command uses the line of the innermost frame at that address, which is the inlined function if a function is inlined there. first is an offset from that line, with a negative value for lines before it. The command marks the line with >.

n

Show or set the default numeric radix for REPL expressions.

n [8|10|16]
set

Define a convenience variable that you can use in expressions as $.

set <$name> <expression>
undisplay

Stop showing displays at every stop.

undisplay <number>...
undisplay *
unset

Remove a convenience variable.

unset <$name>
vars

List the defined convenience variables and result slots.

vars
x

Search for symbols by fuzzy name match.

x [module!]<query>

module! searches the modules whose names match it, which may use * and ?. A query with * or ? is a wildcard pattern. Otherwise each space-separated term must match, fuzzily or by its operator: ^ prefix, $ suffix, ' exact substring (quote such a term: x "'Heap"), ! must not match.