Luaexts

Overview

Luaexts is an extension for Windbg (and the other dbgeng-based debuggers) that provides access to the dbgeng COM API from Lua. It also implements a lightweight framework for writing extensions in Lua.

Project source: https://bitbucket.org/kbhutchinson/luaexts/
Project documentation: https://luaexts.readthedocs.io/

Getting started

  • Download luaexts-x86.zip and/or luaexts-x64.zip, depending on your debugger’s bitness, and unpack into your .extpath.

  • Within Windbg, run the following command: .load luaexts

  • To verify that the extension loaded correctly, run the following command:

    !lua say('success')
    

The growing list of supported dbgeng API functions can be accessed through the global table dbgeng. The table is split up into sub-tables matching the organization of the dbgeng API itself. So the functions from the IDebugSymbols interface (as well as IDebugSymbols2, etc) can be found in the dbgeng.symbols table.

As an example, here’s how to call the IDebugSymbols::GetSymbolTypeId function, use the return values to call the IDebugSymbols::GetTypeName function, and then print the type name of a variable named foo that exists in the current scope:

!lua local module, typeid = dbgeng.symbols.get_symbol_type_id( 'foo' ) say( dbgeng.symbols.get_type_name( module, typeid ) )

or without the temporary variables:

!lua say( dbgeng.symbols.get_type_name( dbgeng.symbols.get_symbol_type_id( 'foo' ) ) )

Small side note: A global function called say() is available that takes the place of Lua’s normal print() function: it prints whatever is given to it and appends a newline. The print() function has been overridden to output without a newline.

Building

The dbgeng headers and libs, required to build luaexts, are not included in this repository because I’m unsure of their redistribution license. So to build luaexts, you’ll need to do the following:

  • Clone the luaexts repository.

  • Retrieve the dbgeng headers and libs.

    • Once you have Windbg installed, the headers can be found in <install-dir>\Debuggers\inc and the libs in <install-dir>\Debuggers\lib. Copy the headers to luaexts\inc and the libs to the appropriate platform directory under luaexts\lib.
  • Build luaexts.sln with Visual Studio.

  • Binaries will be placed in directories under luaexts\bin.

Remember that after building locally, in addition to luaexts.dll, you also need the contents of luaexts\src\luaexts\lua copied to your Windbg extension path, next to the DLL or in a luaexts directory next to the DLL.

General usage

Using the facilities provided by luaexts is usually done at the debugger’s command prompt by entering extension commands, or by writing Lua scripts and running them. This section will discuss the commands that drive these interactions.

The !lua command

The primary interface point for using luaexts is the !lua command, which consumes the rest of the command line as a chunk of Lua code, and simply runs it. Quotation marks surrounding the Lua code are not required, as the dbgeng command parser will automatically consume all text until the next semicolon, which is the debugger’s command-separation marker. If a semicolon is needed within the Lua code itself, then enclosing quotation marks are required, to prevent the dbgeng command parser from interpreting the chunk as multiple dbgeng commands. Fortunately, semicolons as statement-termination markers are optional in Lua syntax, so they are needed very rarely.

Each !lua command runs as a separate Lua chunk. This means that variables declared as local will be in scope only during the execution of one command. Variables assigned to, but not declared as local, will become global variables, available across all subsequent chunks run by luaexts. This can be useful, but care must be taken, because the memory being used by data structures that are pointed to by global variables cannot be freed by the Lua garbage collector as long as they are alive. Assigning nil to a global variable will remove the reference to the data the variable was pointing to, at which point the data will become a candidate for garbage collection.

Lua’s print() function, which normally outputs to stdout, has been replaced by a function that directs output to the debugger command window. Another slight change is that usually Lua’s print() will append a newline, but the print() provided by luaexts does not append a newline, in order to provide more control over exact text output. Instead a global say() function exists that automatically appends a newline.

As an example, here’s how to call the IDebugSymbols::GetSymbolTypeId function, use the return values to call the IDebugSymbols::GetTypeName function, and then print the type name of a variable named foo that exists in the current scope:

!lua local module, typeid = dbgeng.symbols.get_symbol_type_id( 'foo' ) say( dbgeng.symbols.get_type_name( module, typeid ) )
Running scripts: dofile()

Although the !lua command provides the full expressiveness of Lua, it can be tedious to compose complicated code chunks at the debugger command line. We can take advantage of built-in Lua functionality to ease the pain. Lua provides a dofile() function that takes a file path, loads the file as a Lua code chunk, and runs it. Like the scoping of !lua chunks, variables declared as local within the file will be scoped to the file’s chunk, while variables assigned to but not declared local will become global and available to any subsequent chunks run by luaexts.

Developing a script file can then be easily done by opening the file in your favorite text editor, making changes, and then running !lua dofile('path\to\script.lua') from the debugger command line to test each change. (Protip: In Windbg, the previous command can be retrieved from the command history by pressing the Up arrow key when keyboard focus is in the command line input field.)

Running registered commands: !luacmd

Extensions written for luaexts can expose their functionality in two ways. First, they can simply provide named functions to call, either globally scoped or within namespace tables. Second, extensions can register commands that can then be run using the !luacmd command.

Registered commands are functions that take advantage of the debugger engine’s built-in command line parser to automatically parse and tokenize a user-entered debugger command into arguments for the function.

As an example, imagine that an extension would like to expose a function for adding two numbers and printing the result with a label. The simplest way to call such a function using the !lua command would be like so:

!lua add_and_print( 'three', 2, 1 )

With an appropriate registered command, it could be run like this:

!luacmd add_and_print three 2 1

Although at first glance that might not appear very helpful, it has a couple of benefits. One is that the debugger engine’s command line parser has a fair amount of intelligence, and can perform tasks like automatic expression parsing and evaluation, as well as string tokenization for one-word strings so they can be given without requiring quotation marks.

The other main benefit is that registered commands can be used with user-named debugger aliases. Aliases work by replacing aliased text with substitute text. However, aliases cannot take arguments to insert into the substitute text; it is a simple, straightforward replacement. Since most Lua function calls require a closing parenthesis at the end, it would be impossible to define an alias that can be given just the three function arguments and expand into the first code example above. The best that could be done would be:

as !ap !lua add_and_print(

which would need to be called as:

!ap 'three', 2, 1 )

As !luacmd does not use a closing parenthesis, a suitable alias for an appropriate registered command could be defined easily like this:

as !ap !luacmd add_and_print

and then called like this:

!ap three 2 1

As with standard dbgeng extensions, luaexts registered commands can be run in unqualified if there is no ambiguity in the command name, or can be run fully qualified leading with the extension name to resolve ambiguity:

!luacmd add_and_print three 2 1
!luacmd some_ext.add_and_print three 2 1
Finding registered commands: !luahelp

luaexts provides a help mechanism similar to the help mechanism for standard dbgeng extensions. Executing the !luahelp command with no arguments will list all registered commands along with a brief description of the command. The !luahelp command can also be given a registered command name, either qualified or unqualified, to display more detailed help for the given command.

Resetting luaexts: !reinitialize

The !reinitialize command will reset the internal Lua virtual machine, wiping out all global variables and freeing memory allocated by Lua. It will then reinitialize the extension’s configuration by rereading the configuration files and reloading all designated Lua extensions.

This command can be very helpful while implementing a Lua extension, to reset luaexts to a pristine state, or simply to reload functions to test changes.

API

The luaexts API is divided into two categories: 1) the exposed dbgeng COM API; and 2) the additional API that luaexts provides, sometimes as higher level constructs on top of the dbgeng API like cppobj, and sometimes as Lua-extension scaffolding like register_extension().

luaexts

Global functions

Most of the API provided by luaexts is scoped within an appropriately named global table. However, there are a number of global functions that are accessible without prefixing.

print(anything) → nil

Takes any number of arguments of any type, converts them to strings, and outputs those strings to the debugger’s output window with no other formatting.

say(anything) → nil

Exactly like print(), but appends a newline to whatever is output.

dml_print(anything) → nil

Similar to print(), but outputs using debugger markup language (DML).

cppobj

cppobj provides a high level interface for working with C++ objects. The goal is to allow intuitive manipulation of those objects through familiar syntax.

For example, here’s how to wrap an object named foo from the current scope, and print the value of its bar data member:

local foo = cppobj.new( 'foo' )
print( foo.bar )

Lua’s metatable feature is used to overload the indexing operation performed by foo.bar, in order to return a new cppobj for the bar data member, which is then stringified. Stringification is overloaded to return a dbgeng “view” of an object, i.e., the same string that the dbgeng COM API would return when asked to return an object as text. A native Lua value can be retrieved for fundamental types by using cppobj.value().

Due to this overloading of the indexing operation, and the fact that object methods in Lua are also implemented by overloading indexing, most of the functions that operate on cppobj objects are instead implemented as class functions that simply take the cppobj as a paramater.

Class Functions

Class functions are accessible through the global cppobj table. Many of them operate on a cppobj, and return information about the wrapped C++ object.

cppobj.new(expr) → cppobj

Creates a new cppobj, representing a C++ symbol.

Parameters:expr (string) – C++ expression that evaluates to a symbol
Returns:New cppobj representing the given symbol
cppobj.is_cppobj(value) → boolean

Checks whether the given Lua value is a cppobj.

Parameters:value – Lua value to check
Returns:True if value is a cppobj, otherwise false
cppobj.value(obj) → Lua value

For fundamental types (cppobj.kind() returns “base”, “enum”, or “pointer”), returns an object’s value as an appropriately typed Lua value.

For array types, (cppobj.kind() returns “array), returns the memory offset of the array.

For other types, returns nil.

Parameters:obj (cppobj) – Object whose value to return
cppobj.kind(obj) → string

Returns the “kind” of a C++ object. The kind will be one of the following values:

  • base: Fundamental type like bool, char, int, float, etc
  • enum: Enum value
  • pointer
  • array
  • class: Class instance
  • function
  • unknown: Some other, unrecognized kind
Parameters:obj (cppobj) – Object whose kind to return
cppobj.type(obj) → string

Returns an object’s type.

Parameters:obj (cppobj) – Object whose type to return
cppobj.name(obj) → string

Returns an object’s name, usually the variable or field name.

Parameters:obj (cppobj) – Object whose name to return
cppobj.long_name(obj) → string

Returns an object’s “long” name, which is a fully qualified expression that is valid for the current scope.

Parameters:obj (cppobj) – Object whose long name to return
cppobj.offset(obj) → integer

Returns an object’s memory offset in the debugging target’s memory.

Parameters:obj (cppobj) – Object whose offset to return
cppobj.size(obj) → integer

Returns an object’s size.

Parameters:obj (cppobj) – Object whose size to return
cppobj.type_id(obj) → integer

Returns an object’s type id. This id is used in various dbgeng COM API functions.

Parameters:obj (cppobj) – Object whose type id to return
cppobj.type_module(obj) → integer

Returns the base memory offset of the module that the object’s type is from. This is effectively an id for the module, and is used in various dbgeng COM API functions.

Parameters:obj (cppobj) – Object whose module to return
cppobj.address_of(obj) → cppobj

Returns a new cppobj representing a pointer to obj.

Parameters:obj (cppobj) – Object to create a pointer to
cppobj.dereference(obj) → cppobj

Given a cppobj representing a pointer, returns a new cppobj representing the pointee.

Parameters:obj (cppobj) – Object to dereference
cppobj.bases(obj) → array[ cppobj ]

Returns an array of cppobj objects that are the base class representations of obj.

Parameters:obj (cppobj) – Object whose base class representations to return
cppobj.members(obj) → array[ cppobj ]

Returns an array of cppobj objects that are the data members of obj.

Parameters:obj (cppobj) – Object whose data members to return
Overloaded Operators

Overloaded operators comprise the remainder of the interactions with and between cppobj objects.

cppobj.__index(name) → cppobj

The indexing operator (. or []) is overloaded to return a new cppobj representing a data member of the cppobj being indexed.

Assuming foo is a formerly created cppobj, the following retrieves its bar data member as a cppobj:

local bar = foo.bar
-- equivalent:
local bar = foo[ 'bar' ]
cppobj.__eq(cppobj) → boolean

The equality operator (==) is overloaded to test C++ objects for equality, according to the following rules:

  • arrays are treated as pointers
  • pointers, base, and enum types are compared as numbers
  • class types are considered equal if two objects represent the same type at the same memory offset

If the first operand is a cppobj, any other equality result will be false.

cppobj.__sub(cppobj) → number
cppobj.__sub(number) → cppobj or number

The subtraction operator (-) is overloaded to perform subtraction with C++ objects, according to the following rules:

  • if the 1st operand is a cppobj pointer or array, and the 2nd operand is:
    • cppobj pointer or array of the same type
      • result is the scaled distance between the two memory locations, scaled by the object size
    • cppobj base integral type
      • result is a new pointer, offset by the given scaled distance
    • Lua integer
      • result is a new pointer, offset by the given scaled distance
  • if the 1st operand is a cppobj base type or enum, and the 2nd operand is:
    • cppobj base type or enum or Lua number; result is the difference of the two operands
  • if the 1st operand is a Lua value, and the 2nd operand is:
    • cppobj base type or enum or Lua number; result is the difference of the two operands
  • otherwise, the result is nil

dbgeng

The dbgeng COM API is divided into several categories of COM objects, each relating to a specific set of functionality. The provided Lua functions are intended to be a thin facade over the actual COM functions, and so are patterned very closely after them.

Global data

dbgeng.ANY_ID

Used with functions that take an id number to let the engine choose the id.

dbgeng.hr

Table containing HRESULT codes, with string names as keys and their corresponding numeric values. Contains at least the following keys:

  • S_OK
  • S_FALSE
  • E_FAIL
  • E_INVALIDARG
  • E_NOINTERFACE
  • E_OUTOFMEMORY
  • E_UNEXPECTED
  • E_NOTIMPL
  • ERROR_ACCESS_DENIED : numeric value is the evaluation of HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED)

The dbgeng COM API is painstakingly implemented as functions that return HRESULT values, using out parameters to return values that are not suited to a simple HRESULT. The Lua functions that wrap the COM functions try to return sensible Lua values when they can, but when the underlying COM function returns an HRESULT that is not considered a success value, they almost always fall back to returning three values:

  • nil
  • a string value matching one of the HRESULT keys above
  • the corresponding numeric HRESULT value

Those return values should make it easy to determine which specific HRESULT was returned by comparing the strings directly or by comparing with the value of that key in the table.

For example, when calling dbgeng.symbolgroup.expand_symbol(), if the symbol cannot be expanded because it is already at the maximum expansion depth, the function will return nil, 'E_INVALIDARG', and the E_INVALIDARG numeric value. So complete error handling can be done as follows:

local expanded, hrstr, hrnum = sg:expand_symbol( index, true )
if expanded then
    -- success
elseif expanded == false then
    -- no children
elseif hrstr == 'E_INVALIDARG' then
    -- already at max expansion
elseif hrnum == dbgeng.hr.E_INVALIDARG then
    -- same as above elseif clause
elseif hrnum == dbgeng.hr.E_OUTOFMEMORY then
    -- memory allocation failed

    ... -- etc, more error handling
end

See HRESULT Values for common HRESULT return values and their usual meanings.

dbgeng.outctl

Table containing values that are used to control output. The values should be combined into a bitfield.

The lower bits of the bitfield must be exactly one of the following values:

  • THIS_CLIENT : Output generated by methods called by this client will be sent only to this client’s output callbacks.
  • ALL_CLIENTS : Output will be sent to all clients.
  • ALL_OTHER_CLIENTS : Output will be sent to all clients (except to the client that generated the output).
  • IGNORE : Output will be discarded immediately and will not be logged or sent to callbacks.
  • LOG_ONLY : Output will be logged but not sent to callbacks.

The higher bits of the bitfield may contain a combination of zero or more of the following values:

  • NOT_LOGGED : Do not put output from this client in the global log file.
  • OVERRIDE_MASK : Sends output to clients regardless of whether the client’s output mask allows it.
  • DML : For output that supports Debugger Markup Language (DML), sends the output in DML format.

As an alternative to creating a custom output control bitfield value, you can use one of the following values:

  • AMBIENT_DML : Sets the new output control to the same value as the current output control and specifies that the output will be in DML format.
  • AMBIENT_TEXT : Sets the new output control to the same value as the current output control and specifies that the output will be in text format.
  • AMBIENT : Same as AMBIENT_TEXT.

See DEBUG_OUTCTL_XXX.

dbgeng.control

The control functions are all accessible from the global dbgeng.control table, and represent the functions from the IDebugControl interfaces of the dbgeng COM API.

Functions
dbgeng.control.add_assembly_options(options) → boolean

Turns on some of the assembly and disassembly options. The given options will be added to the existing options. See AddAssemblyOptions.

Parameters:options (integer) – bitfield, combining values from the asmopt table
Returns:true if successful
dbgeng.control.add_breakpoint(type, id) → dbgeng.breakpoint

Adds a breakpoint. type can be one of the values from the dbgeng.breakpoint.type table. See AddBreakpoint.

Parameters:
Return type:

dbgeng.breakpoint

dbgeng.control.add_engine_options(options) → boolean

Turns on some of the debugger engine’s options, by combining the given bitfield with the existing options using bitwise OR. Possible bitflag values can be found in the engopt table. See AddEngineOptions.

Parameters:options (integer) – bitfield, combining values from the engopt table
Returns:true if successful
dbgeng.control.add_extension(path) → integer

Loads an extension library into the debugger engine. If the extension library is already loaded, simply returns the handle, the library will not be loaded again. See AddExtension.

Parameters:path (string) – fully qualified path to the extension library to load
Returns:handle to the loaded library
dbgeng.control.call_extension(handle, function, argstr) → boolean

Calls an extension library function. See CallExtension.

Parameters:
  • handle (integer) – handle to the extension library, returned by add_extension(); if set to 0, the engine will walk the extension library chain search for the function
  • function (string) – name of the extension function to call
  • argstr (string) – parsed into arguments by the extension as if typed at the command prompt
Returns:

true if called successfully

dbgeng.control.disassemble(offset, flags) → string, integer

Disassembles a processor instruction in the target’s memory. See Disassemble.

Parameters:
  • offset (integer) – location in the target’s memory of the instruction to disassemble
  • flags (integer) – bitfield of flags that affect the behavior of the function; currently the only flag that can be set is dbgeng.control.disasm_flag.EFFECTIVE_ADDRESS, which will instruct the engine to computer and display the effective address from the current register information
Returns:

two values, the first being the disassembled instruction as a string, and the second being the memory location of the following instruction

dbgeng.control.execute(outctl, command, flags) → boolean

Executes the specified debugger commands, as if typed at the command prompt. See Execute.

Parameters:
  • outctl (integer) – bitfield, combining values from the dbgeng.outctl table
  • command (string) – command string to execute, may contain multiple commands
  • flags (integer) – bitfield, combining values from the execute_flag table
dbgeng.control.get_assembly_options() → integer

Returns the assembly and disassembly options that affect how the debugger engine assembles and disassembles processor instructions for the target. See GetAssemblyOptions.

Returns:bitfield containing a combination of values from the asmopt table
dbgeng.control.get_breakpoint_by_id(id) → breakpoint

Returns the dbgeng.breakpoint with the specified breakpoint id. See GetBreakpointById.

If a breakpoint with the given id is not found, belongs to another process, or is private, returns nil.

Parameters:id (integer) – id of the breakpoint to return
Return type:dbgeng.breakpoint
dbgeng.control.get_breakpoint_by_index(index) → breakpoint

Returns the breakpoint at the specified index. See GetBreakpointByIndex.

If a breakpoint with the given index is not found or is private, returns nil.

Parameters:index (integer) – zero-based index of the breakpoint to return, ranging from 0 to the number of defined breakpoints; this is specific to the current process
Return type:dbgeng.breakpoint
dbgeng.control.get_code_level() → integer

Returns the current code level and is mainly used when stepping through code. See GetCodeLevel.

Returns:one of the values from the level table
dbgeng.control.get_engine_options() → integer

Returns the current engine options. See GetEngineOptions.

Returns:bitfield containing the engine options, which is a combination of the values in the engopt table
dbgeng.control.get_expression_syntax() → integer

Returns the current syntax that the engine is using for evaluating expressions. See GetExpressionSyntax.

Returns:one of the values from the expr table
dbgeng.control.get_expression_syntax_names(index) → string, string

Returns the full and abbreviated names of an expression syntax. See GetExpressionSyntaxNames.

Parameters:index (integer) – index of the expression syntax, which should be between zero and the number returned by get_number_expression_syntaxes() minus one.
Returns:two values, the first being the abbreviated name of the expression syntax, and the second being the full name
dbgeng.control.get_interrupt() → boolean

Checks whether a user interrupt was issued. If a user interrupt was issued, it’s cleared when this function is called. Examples of user interrupts include pressing Ctrl+C or pressing the Stop button in a debugger. Calling :func:.set_interrupt also causes a user interrupt. See GetInterrupt.

Returns:true if an interrupt has been requested, otherwise false
dbgeng.control.get_number_expression_syntaxes() → integer

Returns the number of expression syntaxes that are supported by the engine. See GetNumberExpressionSyntaxes.

Returns:number of supported syntaxes
dbgeng.control.get_stack_trace(frmoff, stkoff, instoff, numframes) → array of stack frame data

Returns the frames at the top of the specified call stack. See GetStackTrace.

Parameters:
  • frmoff (integer) – memory offset of the stack frame at the top of the stack; if zero, the current frame pointer is used
  • stkoff (integer) – memory offset of the current stack; if zero, the current stack pointer is used
  • instoff (integer) – memory offset of the instruction of interest for the function at the top of the stack; if zero, the current instruction pointer is used
  • numframes (integer) – number of frames to retrieve
Returns:

array of tables representing the requested stack frames, each of which contains the following fields:

  • instruction_offset : memory offset of the related instruction for the stack frame; typically, the return address for the next stack frame, or the current instruction pointer if the frame is at the top of the stack
  • return_offset : memory offset of the return address for the stack frame; typically, the related instruction for the previous stack frame
  • frame_offset : memory offset of the stack frame, if known
  • stack_offset : memory offset of the processor stack
  • func_table_entry : memory offset of the function entry point for this frame, if available
  • params : array containing the first four stack slots passed to the function, if available
  • virtual : boolean, set to true if this stack frame was generated by the debugger during unwinding; set to false if it was formed from a thread’s current context
  • frame_number : index of the frame from the top of the stack, which has index 0

dbgeng.control.is_pointer_64bit() → boolean

See IsPointer64Bit.

Returns:true if the effective processor uses 64-bit pointers, otherwise false
dbgeng.control.output_disassembly_lines(outctl, previous_lines, total_lines, offset, flags) → table of memory location data

Disassembles several processor instructions and sends the resulting assembly instructions to the output callbacks. See OutputDisassemblyLines.

Parameters:
  • outctl (integer) – combination of flags from dbgeng.outctl that control output
  • previous_lines (integer) – number of lines of instructions before offset to include in the output
  • total_lines (integer) – number of lines of instructions to include in the output
  • offset (integer) – memory location to disassemble, along with surrounding instructions depending on other arguments
  • flags (integer) – bitfield, combining values from the disasm_flag table
Returns:

table containing the following fields:

  • offset_line : line number in the output that contains the instruction at offset
  • start_offset : memory location of the first instruction included in the output
  • end_offset : memory location of the instruction after the last disassembled instruction
  • line_offsets : array that contains the memory location of each instruction included in the output; if the output for an instruction spans multiple lines, the array element corresponding to the first line of output will contain the address of the instruction

New in version 1.1.0.

dbgeng.control.remove_assembly_options(options) → boolean

Turns off some of the assembly and disassembly options. The given options will be removed from the existing options. See RemoveAssemblyOptions.

Parameters:options (integer) – bitfield, combining values from the asmopt table
Returns:true if successful
dbgeng.control.remove_breakpoint(bp) → boolean

Removes the given breakpoint. See RemoveBreakpoint.

Parameters:bp (breakpoint) – breakpoint to remove
Returns:true if breakpoint was successfully removed
dbgeng.control.remove_engine_options(options) → boolean

Turns off some of the debugger engine’s options, by combining the complement of the given bitfield with the existing options using bitwise AND. Possible bitflag values can be found in the engopt table. See RemoveEngineOptions.

Parameters:options (integer) – bitfield, combining values from the engopt table
Returns:true if successful
dbgeng.control.remove_extension(handle) → boolean

Unloads an extension library. See RemoveExtension.

Parameters:handle (integer) – handle of the extension to unload, returned from add_extension()
Returns:true if successful
dbgeng.control.set_assembly_options(options) → boolean

Changes the assembly and disassembly options. The given options will completely replace the existing options. See SetAssemblyOptions.

Parameters:options (integer) – bitfield, combining values from the asmopt table
Returns:true if successful
dbgeng.control.set_code_level(level) → boolean

Sets the current code level and is mainly used when stepping through code. See SetCodeLevel.

Parameters:level (integer) – one of the values from the level table
Returns:true if successful
dbgeng.control.set_engine_options(options) → boolean

Changes the debugger engine’s options, completely replacing the existing options. Possible bitflag values can be found in the engopt table. See SetEngineOptions.

Parameters:options (integer) – bitfield, combining values from the engopt table
Returns:true if successful
dbgeng.control.set_expression_syntax(syntax) → boolean

Sets the syntax that the engine will use to evaluate expressions. See SetExpressionSyntax.

Parameters:syntax (integer) – one of the values from the expr table
Returns:true if successful
dbgeng.control.set_expression_syntax_by_name(syntax) → boolean

Sets the syntax that the engine will use to evaluate expressions, by syntax name. See SetExpressionSyntaxByName.

Parameters:syntax (string) –

one of the following values:

  • "MASM" : expressions will be evaluated according to MASM syntax
  • "CPLUSPLUS" : expressions will be evaluated according to C++ syntax
Returns:true if successful
dbgeng.control.set_interrupt(flags) → boolean

Registers a user interrupt or breaks into the debugger. See SetInterrupt.

Parameters:flags (integer) – one of the values from the interrupt table
Returns:true if successful
Other
dbgeng.control.asmopt

Table containing assembly and disassembly options that affect how the debugger engine assembles and disassembles processor instructions for the target. Contains the following values, which are intended to be combined in a bitfield:

  • VERBOSE : When set, additional information is included in the disassembly
  • NO_CODE_BYTES : When set, the raw bytes for an instruction are not included in the disassembly
  • IGNORE_OUTPUT_WIDTH : When set, the debugger ignores the width of the output display when formatting instructions during dissamebly
  • SOURCE_LINE_NUMBER : When set, each line of dissembly output is prefixed with the line number of the source code provided by symbol information

See DEBUG_ASMOPT_XXX.

dbgeng.control.disasm_flag

Table containing options controlled some disassembly functions. Contains the following values, which are intended to be combined in a bitfield:

  • EFFECTIVE_ADDRESS : Compute the effective address from the current register information.
  • MATCHING_SYMBOLS : If the address of the instruction has an exact symbol match, output the symbol.
  • SOURCE_LINE_NUMBER : Include the source line number of the instruction in the output.
  • SOURCE_FILE_NAME : Include the source file name in the output.

See the table in the documentation for OutputDisassembly.

dbgeng.control.engopt

Table containing global options that affect the behavior of the debugger engine. Contains the following values, which are intended to be combined in a bitfield:

  • IGNORE_DBGHELP_VERSION : The debugger engine generates a warning instead of an error if the version of the DbgHelp DLL does not match the version of the debugger engine.
  • IGNORE_EXTENSION_VERSIONS : Disable version checking for extensions.
  • ALLOW_NETWORK_PATHS : Network shares can be used for loading symbols and extensions. This option cannot be set if DISALLOW_NETWORK_PATHS is set.
  • DISALLOW_NETWORK_PATHS : Network shares cannot be used for loading symbols and extensions. This option cannot be set if ALLOW_NETWORK_PATHS is set.
  • NETWORK_PATHS : Bitwise OR of ALLOW_NETWORK_PATHS and DISALLOW_NETWORK_PATHS.
  • IGNORE_LOADER_EXCEPTIONS : Ignore expected first-chance exceptions that are generated by the loader in certain versions of Windows.
  • INITIAL_BREAK : Break into the debugger at the target’s initial event.
  • INITIAL_MODULE_BREAK : Break into the debugger when the target loads its first module.
  • FINAL_BREAK : Break into the debugger at the target’s final event. In a live user-mode target, this is when the process exits. It has no effect in kernel mode.
  • NO_EXECUTE_REPEAT : When given an empty command, the debugger engine does not repeat the last command.
  • FAIL_INCOMPLETE_INFORMATION : Prevent the debugger from loading modules whose images cannot be mapped.
  • ALLOW_READ_ONLY_BREAKPOINTS : Allow the debugger engine to manipulate page protections on the target to allow for setting software breakpoints in a read-only section of memory.
  • SYNCHRONIZE_BREAKPOINTS : In live user-mode debugging, the engine performs extra work when inserting and removing breakpoints to ensure that all threads in the target have a consistent breakpoint state at all times.
  • DISALLOW_SHELL_COMMANDS : Disallow executing shell commands through the debugger. After this option has been set, it cannot be unset.
  • KD_QUIET_MODE : Turn on quiet mode. For more info see the documentation for the sq command.
  • DISABLE_MANAGED_SUPPORT : Disables debugger engine support for managed code. If support for managed code is already in use, this option has no effect.
  • DISABLE_MODULE_SYMBOL_LOAD : The debugger does not load symbols for modules that are loaded while this flag is set.
  • DISABLE_EXECUTION_COMMANDS : Prevents any commands that would cause the target to begin executing.
  • DISALLOW_IMAGE_FILE_MAPPING : Disallows mapping of image files from disk.
  • PREFER_DML : The debugger runs DML-enhanced versions of commands and operations by default.
  • DISABLESQM : Disables upload of Software Quality Metrics (SQM) data.
  • DISABLE_STEPLINES_OPTIONS

See DEBUG_ENGOPT_XXX.

dbgeng.control.execute_flag

Table containing options that control the operation of execute(). Contains the following values:

  • ECHO : The command string is sent to the output.
  • NOT_LOGGED : The command string is not logged. This is overridden by ECHO.
  • NO_REPEAT : If command is an empty string, do not repeat the last command, and do not save the current command string for repeat execution later.

See the table in the documentation for Execute.

dbgeng.control.expr

Table containing values that represent possible expression evaluation syntaxes. Contains the following values:

  • MASM : Expressions will be evaluated according to MASM syntax.
  • CPLUSPLUS : Expressions will be evaluated according to C++ syntax.

See the table in the documentation for GetExpressionSyntax.

dbgeng.control.interrupt

Table containing values that control the operation of set_interrupt(). Contains the following values:

  • ACTIVE : If the target is running, the engine will request a break into the debugger. This request might time out. Otherwise, when the target is suspended, the engine will register a user interrupt.
  • PASSIVE : The engine will register a user interrupt.
  • EXIT : See documentation on MSDN.

See table in the documentation for SetInterrupt.

dbgeng.control.level

Table containing values that represent possible code stepping levels. Contains the following values:

  • SOURCE : When stepping through code on the target, the size of a single step will be a line of source code.
  • ASSEMBLY : When stepping through code on the target, the size of a single step will be a single processor instruction.

See the table in the documentation for GetCodeLevel.

dbgeng.symbols

The symbols functions are accessible from the global dbgeng.symbols table, and represent the functions from the IDebugSymbols interfaces of the dbgeng COM API.

Functions
dbgeng.symbols.create_symbol_group() → dbgeng.symbolgroup

Creates a new symbol group. See CreateSymbolGroup2.

Return type:dbgeng.symbolgroup
dbgeng.symbols.get_module_name_string(which, index, base) → string

Returns the name of the specified module. See GetModuleNameString.

Parameters:
  • which (integer) – which of the module’s names to return; should be a value from the modname table
  • index (integer) – index of the module; if set to dbgeng.ANY_ID, the base parameter is used instead
  • base (integer) – if the index paramate is dbgeng.ANY_ID, specifies the module base address; otherwise, it’s ignored
Returns:

name of the specified module

dbgeng.symbols.get_symbol_type_id(symbol) → integer, integer

Returns the module and type id for a symbol. See GetSymbolTypeId.

Parameters:symbol (string) – expression of the symbol whose type id is requested
Returns:two values, the first being the module base address containing the symbol; the second being the type id for the given expression
dbgeng.symbols.get_type_id(module, name) → integer

Returns the type id for a type given its module and name. See GetTypeId.

Parameters:
  • module (integer) – module base address of the module to which the type belongs
  • name (string) – type name or symbol expression whose type id is requested
Returns:

type id of the symbol

dbgeng.symbols.get_type_name(module, typeid) → string

Returns the name of a type specified by its module and type id. See GetTypeName.

Parameters:
  • module (integer) – module base address of the module to which the type belongs
  • typeid (integer) – specifies the type id of the type
Returns:

name of the type

dbgeng.symbols.get_type_size(module, typeid) → integer

Returns the size of a type specified by its module and type id. See GetTypeSize.

Parameters:
  • module (integer) – module base address of the module to which the type belongs
  • typeid (integer) – specifies the type id of the type
Returns:

number of bytes of memory an instance of the specified type requires

Other
dbgeng.symbols.modname

Table containing values that control the operation of get_module_name_string(). Contains the following values:

  • IMAGE : image name; this is the name of the executable file, including the extension
  • MODULE : module name; this is usually just the file name without the extension
  • LOADED_IMAGE : loaded image name; unless Microsoft CodeView symbols are present, this is the same as the image name
  • SYMBOL_FILE : symbol file name; the path and name of the symbol file; if no symbols have been loaded, this is the name of the executable file instead
  • MAPPED_IMAGE : mapped image name; in most cases, this is NULL; if the debugger is mapping an image file (for example, during minidump debugging), this is the name of the mapped image

See table in the documentation for GetModuleNameString.

dbgeng.symbolgroup

The symbol group functions are accessible from the global dbgeng.symbolgroup table, and represent the functions from the IDebugSymbolGroup interfaces of the dbgeng COM API.

Symbol group objects are created from the create_symbol_group() function in dbgeng.symbols.

Symbol groups are disposed automatically by garbage collection when the object is no longer referenced by any variables.

All of the symbolgroup methods are object methods, which means they can be called using Lua object method syntax. Assuming a variable sg containing a symbol group object, this call would return the number of symbols contained in the symbol group:

local numsyms = sg:get_number_symbols()

This is really just syntatic sugar for the more verbose:

local numsyms = dbgeng.symbolgroup.get_number_symbols( sg )
Object methods
dbgeng.symbolgroup.add_symbol(symexpr, index) → integer

Adds a symbol to the symbol group. See AddSymbol.

Parameters:
  • symexpr (string) – C++ expression representing the symbol to add, which can include pointer, array, and structure dereferencing
  • index (integre) – desired index within the symbol group for the added symbol; pass dbgeng.ANY_ID to append the symbol to the end
Returns:

index of the newly added symbol

dbgeng.symbolgroup.expand_symbol(index, expand) → boolean

Adds or removes the children of a symbol within the symbol group. See ExpandSymbol.

Parameters:
  • index (integer) – index of the symbol to expand or collapse
  • expand (boolean) – true to expand, false to collapse
Returns:

indication of success of the operation

  • true if the operation succeeded
  • false if the symbol had no children to add
  • if the symbol is already at the maximum expansion depth, so that its children could not be added, returns the three values: nil, 'E_INVALIDARG', and dbgeng.hr.E_INVALIDARG

dbgeng.symbolgroup.get_number_symbols() → integer

Returns the number of symbols in the symbol group. See GetNumberSymbols.

dbgeng.symbolgroup.get_symbol_entry_information(index) → table of symbol information

Returns information about a symbol in a symbol group. See GetSymbolEntryInformation.

Parameters:index (integer) – index of the symbol whose information to retrieve
Returns:table containing the following fields:
  • module : module base address
  • offset : memory location of the symbol
  • id : id of the symbol; if not known, will be equal to dbgeng.INVALID_OFFSET
  • arg64 : interpretation depends on the type of the symbol; if not known, will be 0
  • size : size of the symbol’s value, in bytes
  • type_id : type id of the symbol
  • name_size : size of the symbol’s name, in characters
  • token : managed token of the symbol; if not known or has none, will be 0
  • tag : symbol tag of the symbol; will equal one of the values in the dbgeng.symtag table
  • arg32 : interpretation depends on the type of the symbol; currently, equals the register that holds the value or pointer to the value of the symbol; if the symbol is not held in a register or the register is not known, will be 0
dbgeng.symbolgroup.get_symbol_name(index) → string

Returns the name of a symbol in the symbol group. See GetSymbolName.

Parameters:index (integer) – index of the symbol whose information to retrieve
dbgeng.symbolgroup.get_symbol_offset(index) → integer

Returns the memory location in the target’s memory of a symbol in the symbol group, if the symbol has an absolute address. See GetSymbolOffset.

Parameters:index (integer) – index of the symbol whose information to retrieve
dbgeng.symbolgroup.get_symbol_parameters(start, count) → array of symbol parameter information

Returns symbol parameters that describe the specified symbols from the symbol group. See GetSymbolParameters.

Parameters:
  • start (integer) – index of the first symbol for which to retrieve parameters
  • count (integer) – number of symbols for which to retrieve parameters
Returns:

array of tables, each of which contains the following fields:

  • module : module base address
  • type_id : type id of the symbol
  • parent_symbol : index within the symbol group of the symbol’s parent
  • sub_elements : number of children of the symbol
  • flags : bitfield combination of the values in the symbol_flag table
  • expansion_depth : expansion depth of the symbol within the symbol group; the depth of a child symbol is always one more than the depth of its parent

dbgeng.symbolgroup.get_symbol_register(index) → integer

Returns the index of the register that contains the value or a pointer to the value of a symbol in the symbol group. See GetSymbolRegister.

Parameters:index (integer) – index of the symbol whose information to retrieve
dbgeng.symbolgroup.get_symbol_size(index) → integer

Returns the size of a symbol’s value, in bytes. See GetSymbolSize.

Parameters:index (integer) – index of the symbol whose information to retrieve
dbgeng.symbolgroup.get_symbol_type_name(index) → string

Returns the name of a symbol’s type. See GetSymbolTypeName.

Parameters:index (integer) – index of the symbol whose information to retrieve
dbgeng.symbolgroup.get_symbol_value_text(index) → string

Returns a string representation of a symbol’s value. See GetSymbolValueText.

Parameters:index (integer) – index of the symbol whose information to retrieve
dbgeng.symbolgroup.remove_symbol_by_index(index) → boolean

Removes the specified symbol from the symbol group. Child symbols cannot be removed using this method; the parent symbol must be removed, which will remove the children as well. See RemoveSymbolByIndex.

Parameters:index (integer) – index of the symbol to remove
Returns:true if the operation succeeded, otherwise nil
dbgeng.symbolgroup.remove_symbol_by_name(name) → boolean

Removes the specified symbol from the symbol group. Child symbols cannot be removed using this method; the parent symbol must be removed, which will remove the children as well. See RemoveSymbolByName.

Parameters:name (string) – name of the symbol to remove
Returns:true if the operation succeeded, otherwise nil
dbgeng.symbolgroup.write_symbol(index, value) → boolean

Sets the value of a symbol in the symbol group. See WriteSymbol.

Parameters:
  • index (integer) – index of the symbol to set
  • value (string) – C++ expression that is evaluated to determine the symbol’s new value
Returns:

true if the operation is successful, otherwise nil

Other
dbgeng.symbolgroup.symbol_flag
  • EXPANDED : The children of the symbol are part of the symbol group.
  • READ_ONLY : The symbol represents a read-only variable.
  • IS_ARRAY : The symbol represents an array variable.
  • IS_FLOAT : The symbol represents a floating-point variable.
  • IS_ARGUMENT : The symbol represents an argument passed to a function.
  • IS_LOCAL : The symbol represents a local variable in a scope.

See DEBUG_SYMBOL_XXX.

dbgeng.breakpoint

The breakpoint functions are accessible from the global dbgeng.breakpoint table, and represent the functions from the IDebugBreakpoint interfaces of the dbgeng COM API.

Breakpoints objects are generated from functions in dbgeng.control: add_breakpoint() to create a new breakpoint, and get_breakpoint_by_id() or get_breakpoint_by_index() to retrieve an existing breakpoint.

Breakpoints are removed by calling dbgeng.control.remove_breakpoint() and passing a breakpoint object. They are not removed when the Lua variable goes out of scope or is collected by garbage collection.

All of the breakpoint methods are object methods, which means they can be called using Lua object method syntax. Assuming a variable bp containing a breakpoint object, this call would return the command to be executed when the breakpoint is hit:

local cmd = bp:get_command()

This is really just syntatic sugar for the more verbose:

local cmd = dbgeng.breakpoint.get_command( bp )
Object methods
dbgeng.breakpoint.add_flags(flags) → nil

Adds flags to the breakpoint by combining the given bitfield with existing flags using bitwise OR. Possible flag values can be found in the flag table. See AddFlags.

Parameters:flags (integer) – bitfield, combining values from flag
dbgeng.breakpoint.get_command() → string

Returns the command string that is executed when a breakpoint is triggered. See GetCommand.

dbgeng.breakpoint.get_current_pass_count() → integer

Returns the remaining number of times that the target must reach the breakpoint location before the breakpoint is triggered. See GetCurrentPassCount.

dbgeng.breakpoint.get_data_parameters() → integer, integer

Returns two values:

  • The first is the size in bytes of the memory block whose access triggers the breakpoint.
  • The second is the access type, which will equal one of the values from the access table.

See GetDataParameters.

dbgeng.breakpoint.get_flags() → integer

Returns the flags for a breakpoint, as a bitfield, combining values from the flag table. See GetFlags.

dbgeng.breakpoint.get_id() → integer

Returns the breakpoint’s id. See GetId.

dbgeng.breakpoint.get_match_thread_id() → integer or nil

If a thread has been set for the breakpoint, the breakpoint can be triggered only if that thread hits the breakpoint. If a thread has not been set, any thread can trigger the breakpoint.

Returns the engine thread id that can trigger the breakpoint, or nil if a thread has not been set. See GetMatchThreadId.

dbgeng.breakpoint.get_offset() → integer

Returns the location that triggers the breakpoint. See GetOffset.

dbgeng.breakpoint.get_offset_expression() → string

Returns the expression that evaluates to the location that triggers the breakpoint. See GetOffsetExpression.

dbgeng.breakpoint.get_parameters() → table

Returns most parameter information for a breakpoint in one call, rather than using separate calls for each piece. See GetParameters.

Returns:table with the following named fields:
  • offset : location in the target’s memory that will trigger the breakpoint
  • id : breakpoint id
  • break_type : one of the values from the type table
  • proc_type : type of processor the breakpoint is set for
  • flags : breakpoint flags
  • data_size : for a data breakpoint, the size in bytes of the memory location that will trigger the breakpoint; otherwise, zero
  • data_access_type : for a data breakpoint, one of the values from the access table; otherwise, zero
  • pass_count : number of times the target will hit the breakpoint before it triggers
  • current_pass_count : remaining number of times the target will hit the breakpoint before it triggers
  • match_thread : engine thread id of the thread that can trigger the breakpoint; if any thread can trigger it, dbgeng.ANY_ID
dbgeng.breakpoint.get_pass_count() → integer

Returns the number of times that the target was originally required to reach the breakpoint location before the breakpoint is triggered. See GetPassCount.

dbgeng.breakpoint.get_type() → integer, integer

Returns two values:

  • type of breakpoint, which can be one of the values in the type table
  • type of processor the breakpoint is set for

See GetType.

dbgeng.breakpoint.remove_flags(flags) → nil

Removes flags from a breakpoint, by combining the complement of the given bitfield with the existing flags, using bitwise AND. Possible flag values can be found in the flag table. See RemoveFlags.

Parameters:flags (integer) – bitfield, combining values from flag
dbgeng.breakpoint.set_command(command) → nil

Sets the command string that is executed when a breakpoint is triggered. See SetCommand.

Parameters:command (string) – command string to execute
dbgeng.breakpoint.set_data_parameters(size, access_type) → nil

Sets parameters for a processor breakpoint. See SetDataParameters.

Parameters:
  • size (integer) – size in bytes of the memory location whose access will trigger the breakpoint
  • access_type (integer) – one of the values from the access table
dbgeng.breakpoint.set_flags(flags) → nil

Sets the flags for a breakpoint. See SetFlags.

Parameters:flags (integer) – bitfield, combining values from the flag table
dbgeng.breakpoint.set_match_thread_id(id) → nil

Sets the engine thread id that can trigger the breakpoint. If a thread has been set, the setting can be removed by passing dbgeng.ANY_ID for the id. See SetMatchThreadId.

Parameters:id (integer) – id of the thread that can trigger the breakpoint
dbgeng.breakpoint.set_offset(offset) → nil

Sets the memory location in the target that triggers the breakpoint. See SetOffset.

Parameters:offset (integer) – location in the target’s memory
dbgeng.breakpoint.set_offset_expression(expression) → nil

Sets the expression string that evaluates to the location that triggers the breakpoint. See SetOffsetExpression.

Parameters:expression (string) – expression that evaluates to a location in the target’s memory
dbgeng.breakpoint.set_pass_count(passes) → nil

Sets the number of times that the target must reach the breakpoint location before the breakpoint is triggered. See SetPassCount.

Parameters:passes (integer) – number of passes to trigger the breakpoint
Other
dbgeng.breakpoint.access

Table containing the access types that processor breakpoints can be defined with.

  • READ : Triggered when the CPU reads or writes memory in the breakpoint’s block.
  • WRITE : Triggered when the CPU writes memory in the breakpoint’s block.
  • EXECUTE : Triggered when the CPU fetches the instruction in the breakpoint’s block.
  • IO : Triggered when the I/O port in the breakpoint’s block is accessed.
dbgeng.breakpoint.flag

Table containing bit-flags that affect breakpoint operation.

  • ENABLED : When set, the breakpoint is enabled. When not set, the breakpoint is disabled.
  • ADDER_ONLY : When set, the breakpoint is a private breakpoint, only visible to the client that added it. Other clients will not be able to query for it, and events will not be sent to other clients. Callbacks related to the breakpoint will only be sent to this client.
  • GO_ONLY : When set, the breakpoint will only be triggered if the target is in unrestricted execution. It will not be triggered when stepping through instructions.
  • ONE_SHOT : When set, the breakpoint will automatically be removed the first time it triggers.
  • DEFERRED : When set, the breakpoint is deferred. The engine sets this flag when a breakpoint is defined using a symbolic expression, and the engine can’t evaluate the expression. Every time a module is loaded or unloaded in the target, the engine will attempt to reevaluate the expression. This flag cannot be modified by any client.
dbgeng.breakpoint.type

Table containing types of breakpoints that can be created.

  • CODE: software breakpoint
  • DATA: processor breakpoint

Indices and tables