123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709 |
- /*++
- Copyright (c) 2012 Minoca Corp. All Rights Reserved
- Module Name:
- exts.c
- Abstract:
- This module contains support for loading and running debugger extensions.
- Author:
- Evan Green 10-Sep-2012
- Environment:
- Debug Client
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include "dbgrtl.h"
- #include <minoca/lib/im.h>
- #include <minoca/debug/spproto.h>
- #include <minoca/debug/dbgext.h>
- #include "symbols.h"
- #include "dbgapi.h"
- #include "dbgrprof.h"
- #include "dbgrcomm.h"
- #include "extsp.h"
- #include "../dbgext/extimp.h"
- #include <errno.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- typedef struct _DEBUGGER_EXTENSION {
- LIST_ENTRY ListEntry;
- PSTR BinaryName;
- ULONG Handle;
- LIST_ENTRY ExtensionsHead;
- } DEBUGGER_EXTENSION, *PDEBUGGER_EXTENSION;
- typedef struct _DEBUGGER_EXTENSION_ENTRY {
- LIST_ENTRY ListEntry;
- PSTR Command;
- PEXTENSION_PROTOTYPE Handler;
- PSTR OneLineDescription;
- } DEBUGGER_EXTENSION_ENTRY, *PDEBUGGER_EXTENSION_ENTRY;
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- PDEBUGGER_EXTENSION
- DbgpFindExtension (
- PDEBUGGER_CONTEXT Context,
- PSTR BinaryName
- );
- PDEBUGGER_EXTENSION_ENTRY
- DbgpFindExtensionEntry (
- PDEBUGGER_CONTEXT Context,
- PSTR ExtensionCommand
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- DEBUG_EXTENSION_IMPORT_INTERFACE DbgExports = {
- DEBUG_EXTENSION_INTERFACE_VERSION,
- DbgRegisterExtension,
- DbgOutVaList,
- DbgEvaluate,
- DbgPrintAddressSymbol,
- DbgReadMemory,
- DbgWriteMemory,
- DbgReboot,
- DbgGetCallStack,
- DbgPrintCallStack,
- DbgGetTargetInformation,
- DbgGetTargetPointerSize,
- DbgGetMemberOffset,
- DbgGetTypeByName,
- DbgReadIntegerMember,
- DbgReadTypeByName,
- DbgReadType,
- DbgPrintTypeMember,
- };
- //
- // ------------------------------------------------------------------ Functions
- //
- INT
- DbgInitializeExtensions (
- PDEBUGGER_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine initializes support for debugger extensions and loads any
- extensions supplied on the command line.
- Arguments:
- Context - Supplies a pointer to the application context.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- INITIALIZE_LIST_HEAD(&(Context->LoadedExtensions));
- return 0;
- }
- INT
- DbgLoadExtension (
- PDEBUGGER_CONTEXT Context,
- PSTR BinaryName
- )
- /*++
- Routine Description:
- This routine loads a debugger extension library.
- Arguments:
- Context - Supplies a pointer to the application context.
- BinaryName - Supplies the path to the binary to load.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- PDEBUGGER_EXTENSION ExistingExtension;
- PEXTENSION_ENTRY_INTERNAL ExtensionEntry;
- BOOL ExtensionLinked;
- ULONG Handle;
- PDEBUGGER_EXTENSION NewExtension;
- INT Result;
- ExtensionLinked = FALSE;
- NewExtension = NULL;
- //
- // Ensure a library of the same name is not already loaded.
- //
- ExistingExtension = DbgpFindExtension(Context, BinaryName);
- if (ExistingExtension != NULL) {
- Result = EEXIST;
- goto LoadExtensionEnd;
- }
- //
- // Attempt to load the library. If this fails, cleanup and exit.
- //
- Handle = DbgLoadLibrary(BinaryName);
- if (Handle == 0) {
- Result = EINVAL;
- goto LoadExtensionEnd;
- }
- //
- // Attempt to find the entrypoint. If this fails, cleanup and exit.
- //
- ExtensionEntry = DbgGetProcedureAddress(Handle, EXTENSION_ENTRY_NAME);
- if (ExtensionEntry == NULL) {
- Result = EINVAL;
- DbgOut("Error: Extension entry function %s could not be found.\n",
- EXTENSION_ENTRY_NAME);
- goto LoadExtensionEnd;
- }
- //
- // Allocate space to store the extension information and binary name.
- //
- NewExtension = MALLOC(sizeof(DEBUGGER_EXTENSION));
- if (NewExtension == NULL) {
- Result = ENOMEM;
- goto LoadExtensionEnd;
- }
- RtlZeroMemory(NewExtension, sizeof(DEBUGGER_EXTENSION));
- INITIALIZE_LIST_HEAD(&(NewExtension->ExtensionsHead));
- NewExtension->BinaryName = MALLOC(RtlStringLength(BinaryName) + 1);
- if (NewExtension->BinaryName == NULL) {
- Result = ENOMEM;
- goto LoadExtensionEnd;
- }
- RtlStringCopy(NewExtension->BinaryName,
- BinaryName,
- RtlStringLength(BinaryName) + 1);
- NewExtension->Handle = Handle;
- INSERT_BEFORE(&(NewExtension->ListEntry), &(Context->LoadedExtensions));
- ExtensionLinked = TRUE;
- //
- // Call the entry point and allow the extension to initialize.
- //
- Result = ExtensionEntry(EXTENSION_API_VERSION,
- Context,
- NewExtension,
- &DbgExports);
- if (Result != 0) {
- goto LoadExtensionEnd;
- }
- LoadExtensionEnd:
- if (Result != 0) {
- if (NewExtension != NULL) {
- if (ExtensionLinked != FALSE) {
- LIST_REMOVE(&(NewExtension->ListEntry));
- }
- if (NewExtension->BinaryName != NULL) {
- FREE(NewExtension->BinaryName);
- }
- FREE(NewExtension);
- }
- }
- return Result;
- }
- VOID
- DbgUnloadExtension (
- PDEBUGGER_CONTEXT Context,
- PSTR BinaryName
- )
- /*++
- Routine Description:
- This routine unloads and frees a debugger extension library.
- Arguments:
- Context - Supplies a pointer to the application context.
- BinaryName - Supplies the path to the binary to unload.
- Return Value:
- None.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- PDEBUGGER_EXTENSION Extension;
- PDEBUGGER_EXTENSION_ENTRY ExtensionEntry;
- //
- // Attempt to find the extension.
- //
- Extension = DbgpFindExtension(Context, BinaryName);
- if (Extension == NULL) {
- return;
- }
- //
- // Free all extension entries.
- //
- CurrentEntry = Extension->ExtensionsHead.Next;
- while (CurrentEntry != &(Extension->ExtensionsHead)) {
- ExtensionEntry = LIST_VALUE(CurrentEntry,
- DEBUGGER_EXTENSION_ENTRY,
- ListEntry);
- CurrentEntry = CurrentEntry->Next;
- FREE(ExtensionEntry);
- }
- //
- // Unlink the extension, unload the library, and free the memory.
- //
- LIST_REMOVE(&(Extension->ListEntry));
- DbgFreeLibrary(Extension->Handle);
- FREE(Extension->BinaryName);
- FREE(Extension);
- return;
- }
- VOID
- DbgUnloadAllExtensions (
- PDEBUGGER_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine unloads all debugger extensions.
- Arguments:
- Context - Supplies a pointer to the application context.
- Return Value:
- None.
- --*/
- {
- PDEBUGGER_EXTENSION Extension;
- while (LIST_EMPTY(&(Context->LoadedExtensions)) == FALSE) {
- Extension = LIST_VALUE(Context->LoadedExtensions.Next,
- DEBUGGER_EXTENSION,
- ListEntry);
- DbgUnloadExtension(Context, Extension->BinaryName);
- }
- return;
- }
- INT
- DbgDispatchExtension (
- PDEBUGGER_CONTEXT Context,
- PSTR *Arguments,
- ULONG ArgumentCount
- )
- /*++
- Routine Description:
- This routine dispatches a debugger extension command.
- Arguments:
- Context - Supplies a pointer to the application context.
- Arguments - Supplies an array of strings containing the arguments. The
- first argument is the command itself.
- ArgumentCount - Supplies the count of arguments. This is always at least
- one.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- PSTR Command;
- PSTR CommandCopy;
- PLIST_ENTRY CurrentEntry;
- PLIST_ENTRY CurrentExtension;
- PDEBUGGER_EXTENSION_ENTRY CurrentExtensionEntry;
- PDEBUGGER_EXTENSION Extension;
- INT Status;
- PSTR SubCommand;
- Command = Arguments[0] + 1;
- //
- // If the command is just a !, print out all extensions with a description.
- //
- if (*Command == '\0') {
- //
- // Loop through all registered extension binaries.
- //
- CurrentExtension = Context->LoadedExtensions.Next;
- while (CurrentExtension != &(Context->LoadedExtensions)) {
- Extension = LIST_VALUE(CurrentExtension,
- DEBUGGER_EXTENSION,
- ListEntry);
- CurrentExtension = CurrentExtension->Next;
- DbgOut("%s:\n", Extension->BinaryName);
- //
- // Loop through all extensions of the current binary.
- //
- CurrentEntry = Extension->ExtensionsHead.Next;
- while (CurrentEntry != &(Extension->ExtensionsHead)) {
- CurrentExtensionEntry = LIST_VALUE(CurrentEntry,
- DEBUGGER_EXTENSION_ENTRY,
- ListEntry);
- CurrentEntry = CurrentEntry->Next;
- DbgOut(" !%s - %s\n",
- CurrentExtensionEntry->Command,
- CurrentExtensionEntry->OneLineDescription);
- }
- }
- Status = 0;
- //
- // Find the extension and dispatch it.
- //
- } else {
- //
- // Find the first period, which splits the extension to its subcommand.
- //
- CommandCopy = strdup(Command);
- if (CommandCopy == NULL) {
- return ENOMEM;
- }
- SubCommand = strchr(CommandCopy, '.');
- if (SubCommand != NULL) {
- *SubCommand = '\0';
- SubCommand += 1;
- }
- //
- // Find the extension and dispatch it.
- //
- CurrentExtensionEntry = DbgpFindExtensionEntry(Context, CommandCopy);
- if (CurrentExtensionEntry != NULL) {
- Status = CurrentExtensionEntry->Handler(Context,
- SubCommand,
- ArgumentCount,
- Arguments);
- } else {
- DbgOut("Error: Extension !%s not found.\n", Command);
- Status = ENOENT;
- }
- free(CommandCopy);
- }
- return Status;
- }
- INT
- DbgRegisterExtension (
- PDEBUGGER_CONTEXT Context,
- PVOID Token,
- PSTR ExtensionName,
- PSTR OneLineDescription,
- PEXTENSION_PROTOTYPE Routine
- )
- /*++
- Routine Description:
- This routine registers a debugger extension with the client.
- Arguments:
- Context - Supplies a pointer to the application context.
- Token - Supplies the unique token provided to the extension library upon
- initialization.
- ExtensionName - Supplies the name of the extension to register. This name
- must not already be registered by the current extension or any other.
- OneLineDescription - Supplies a quick description of the extension, no
- longer than 60 characters. This parameter is not optional.
- Routine - Supplies the routine to call when the given extension is
- invoked.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- PDEBUGGER_EXTENSION_ENTRY ExistingEntry;
- PDEBUGGER_EXTENSION Extension;
- PDEBUGGER_EXTENSION_ENTRY NewEntry;
- INT Result;
- NewEntry = NULL;
- //
- // The token is actually just a pointer to the extension structure. Though
- // this is susceptible to tampering, this DLL is loaded in our address
- // space and has already been allowed to run arbitrary code. If it wanted
- // to take the process down, it could have already.
- //
- if (Token == NULL) {
- return EINVAL;
- }
- Extension = (PDEBUGGER_EXTENSION)Token;
- //
- // Descriptions are *not* optional.
- //
- if (OneLineDescription == NULL) {
- return EINVAL;
- }
- //
- // Refuse to register extensions that are already registered.
- //
- ExistingEntry = DbgpFindExtensionEntry(Context, ExtensionName);
- if (ExistingEntry != NULL) {
- Result = EEXIST;
- goto RegisterExtensionEnd;
- }
- NewEntry = MALLOC(sizeof(DEBUGGER_EXTENSION_ENTRY));
- if (NewEntry == NULL) {
- Result = ENOMEM;
- goto RegisterExtensionEnd;
- }
- RtlZeroMemory(NewEntry, sizeof(DEBUGGER_EXTENSION_ENTRY));
- NewEntry->Command = ExtensionName;
- NewEntry->Handler = Routine;
- NewEntry->OneLineDescription = OneLineDescription;
- INSERT_BEFORE(&(NewEntry->ListEntry), &(Extension->ExtensionsHead));
- Result = 0;
- RegisterExtensionEnd:
- if (Result != 0) {
- if (NewEntry != NULL) {
- FREE(NewEntry);
- }
- }
- return Result;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- PDEBUGGER_EXTENSION
- DbgpFindExtension (
- PDEBUGGER_CONTEXT Context,
- PSTR BinaryName
- )
- /*++
- Routine Description:
- This routine finds a loaded debugger extension matching the given binary
- name.
- Arguments:
- Context - Supplies a pointer to the application context.
- BinaryName - Supplies the extension binary name.
- Return Value:
- Returns a pointer to the loaded extension, or NULL if the extension could
- not be found.
- --*/
- {
- PLIST_ENTRY Entry;
- PDEBUGGER_EXTENSION Extension;
- Entry = Context->LoadedExtensions.Next;
- while (Entry != &(Context->LoadedExtensions)) {
- Extension = LIST_VALUE(Entry, DEBUGGER_EXTENSION, ListEntry);
- if (RtlAreStringsEqual(BinaryName, Extension->BinaryName, 1024) !=
- FALSE) {
- return Extension;
- }
- }
- return NULL;
- }
- PDEBUGGER_EXTENSION_ENTRY
- DbgpFindExtensionEntry (
- PDEBUGGER_CONTEXT Context,
- PSTR ExtensionCommand
- )
- /*++
- Routine Description:
- This routine finds the extension entry corresponding to the given extension
- command.
- Arguments:
- Context - Supplies a pointer to the application context.
- ExtensionCommand - Supplies the extension command, not including the
- leading !.
- Return Value:
- Returns a pointer to the extension entry, or NULL if none was registered.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- PLIST_ENTRY CurrentExtension;
- PDEBUGGER_EXTENSION_ENTRY CurrentExtensionEntry;
- PDEBUGGER_EXTENSION Extension;
- BOOL StringsEqual;
- //
- // Loop through all registered extension binaries.
- //
- CurrentExtension = Context->LoadedExtensions.Next;
- while (CurrentExtension != &(Context->LoadedExtensions)) {
- Extension = LIST_VALUE(CurrentExtension, DEBUGGER_EXTENSION, ListEntry);
- CurrentExtension = CurrentExtension->Next;
- //
- // Loop through all extensions of the current binary.
- //
- CurrentEntry = Extension->ExtensionsHead.Next;
- while (CurrentEntry != &(Extension->ExtensionsHead)) {
- CurrentExtensionEntry = LIST_VALUE(CurrentEntry,
- DEBUGGER_EXTENSION_ENTRY,
- ListEntry);
- CurrentEntry = CurrentEntry->Next;
- StringsEqual = RtlAreStringsEqual(CurrentExtensionEntry->Command,
- ExtensionCommand,
- MAX_EXTENSION_COMMAND);
- if (StringsEqual != FALSE) {
- return CurrentExtensionEntry;
- }
- }
- }
- return NULL;
- }
|