windows-nt/Source/XPSP1/NT/sdktools/debuggers/samples/dumpstk/dumpstk.cpp

289 lines
6.7 KiB
C++
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
//----------------------------------------------------------------------------
//
// Simple example of how to open a dump file and get its stack.
//
// This is not a debugger extension. It is a tool that can be used to replace
// the debugger.
//
//
// Copyright (C) Microsoft Corporation, 2000.
//
//----------------------------------------------------------------------------
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <windows.h>
#include <dbgeng.h>
#include "out.hpp"
PSTR g_DumpFile;
PSTR g_ImagePath;
PSTR g_SymbolPath;
ULONG64 g_TraceFrom[3];
IDebugClient* g_Client;
IDebugControl* g_Control;
IDebugSymbols* g_Symbols;
void
Exit(int Code, PCSTR Format, ...)
{
// Clean up any resources.
if (g_Symbols != NULL)
{
g_Symbols->Release();
}
if (g_Control != NULL)
{
g_Control->Release();
}
if (g_Client != NULL)
{
//
// Request a simple end to any current session.
// This may or may not do anything but it isn't
// harmful to call it.
//
// We don't want to see any output from the shutdown.
g_Client->SetOutputCallbacks(NULL);
g_Client->EndSession(DEBUG_END_PASSIVE);
g_Client->Release();
}
// Output an error message if given.
if (Format != NULL)
{
va_list Args;
va_start(Args, Format);
vfprintf(stderr, Format, Args);
va_end(Args);
}
exit(Code);
}
void
CreateInterfaces(void)
{
HRESULT Status;
// Start things off by getting an initial interface from
// the engine. This can be any engine interface but is
// generally IDebugClient as the client interface is
// where sessions are started.
if ((Status = DebugCreate(__uuidof(IDebugClient),
(void**)&g_Client)) != S_OK)
{
Exit(1, "DebugCreate failed, 0x%X\n", Status);
}
// Query for some other interfaces that we'll need.
if ((Status = g_Client->QueryInterface(__uuidof(IDebugControl),
(void**)&g_Control)) != S_OK ||
(Status = g_Client->QueryInterface(__uuidof(IDebugSymbols),
(void**)&g_Symbols)) != S_OK)
{
Exit(1, "QueryInterface failed, 0x%X\n", Status);
}
}
void
ParseCommandLine(int Argc, char** Argv)
{
int i;
while (--Argc > 0)
{
Argv++;
if (!strcmp(*Argv, "-a32"))
{
if (Argc < 4)
{
Exit(1, "-a32 missing arguments\n");
}
for (i = 0; i < 3; i++)
{
int Addr;
Argv++;
Argc--;
sscanf(*Argv, "%i", &Addr);
g_TraceFrom[i] = (ULONG64)(LONG64)(LONG)Addr;
}
}
else if (!strcmp(*Argv, "-a64"))
{
if (Argc < 4)
{
Exit(1, "-a64 missing arguments\n");
}
for (i = 0; i < 3; i++)
{
Argv++;
Argc--;
sscanf(*Argv, "%I64i", &g_TraceFrom[i]);
}
}
else if (!strcmp(*Argv, "-i"))
{
if (Argc < 2)
{
Exit(1, "-i missing argument\n");
}
Argv++;
Argc--;
g_ImagePath = *Argv;
}
else if (!strcmp(*Argv, "-y"))
{
if (Argc < 2)
{
Exit(1, "-y missing argument\n");
}
Argv++;
Argc--;
g_SymbolPath = *Argv;
}
else if (!strcmp(*Argv, "-z"))
{
if (Argc < 2)
{
Exit(1, "-z missing argument\n");
}
Argv++;
Argc--;
g_DumpFile = *Argv;
}
else
{
Exit(1, "Unknown command line argument '%s'\n", *Argv);
}
}
if (g_DumpFile == NULL)
{
Exit(1, "No dump file specified, use -z <file>\n");
}
}
void
ApplyCommandLineArguments(void)
{
HRESULT Status;
// Install output callbacks so we get any output that the
// later calls produce.
if ((Status = g_Client->SetOutputCallbacks(&g_OutputCb)) != S_OK)
{
Exit(1, "SetOutputCallbacks failed, 0x%X\n", Status);
}
if (g_ImagePath != NULL)
{
if ((Status = g_Symbols->SetImagePath(g_ImagePath)) != S_OK)
{
Exit(1, "SetImagePath failed, 0x%X\n", Status);
}
}
if (g_SymbolPath != NULL)
{
if ((Status = g_Symbols->SetSymbolPath(g_SymbolPath)) != S_OK)
{
Exit(1, "SetSymbolPath failed, 0x%X\n", Status);
}
}
// Everything's set up so open the dump file.
if ((Status = g_Client->OpenDumpFile(g_DumpFile)) != S_OK)
{
Exit(1, "OpenDumpFile failed, 0x%X\n", Status);
}
// Finish initialization by waiting for the event that
// caused the dump. This will return immediately as the
// dump file is considered to be at its event.
if ((Status = g_Control->WaitForEvent(DEBUG_WAIT_DEFAULT,
INFINITE)) != S_OK)
{
Exit(1, "WaitForEvent failed, 0x%X\n", Status);
}
// Everything is now initialized and we can make any
// queries we want.
}
void
DumpStack(void)
{
HRESULT Status;
PDEBUG_STACK_FRAME Frames = NULL;
int Count = 50;
printf("\nFirst %d frames of the call stack:\n", Count);
if (g_TraceFrom[0] || g_TraceFrom[1] || g_TraceFrom[2])
{
ULONG Filled;
Frames = new DEBUG_STACK_FRAME[Count];
if (Frames == NULL)
{
Exit(1, "Unable to allocate stack frames\n");
}
if ((Status = g_Control->
GetStackTrace(g_TraceFrom[0], g_TraceFrom[1], g_TraceFrom[2],
Frames, Count, &Filled)) != S_OK)
{
Exit(1, "GetStackTrace failed, 0x%X\n", Status);
}
Count = Filled;
}
// Print the call stack.
if ((Status = g_Control->
OutputStackTrace(DEBUG_OUTCTL_ALL_CLIENTS, Frames,
Count, DEBUG_STACK_SOURCE_LINE |
DEBUG_STACK_FRAME_ADDRESSES |
DEBUG_STACK_COLUMN_NAMES |
DEBUG_STACK_FRAME_NUMBERS)) != S_OK)
{
Exit(1, "OutputStackTrace failed, 0x%X\n", Status);
}
delete Frames;
}
void __cdecl
main(int Argc, char** Argv)
{
CreateInterfaces();
ParseCommandLine(Argc, Argv);
ApplyCommandLineArguments();
DumpStack();
Exit(0, NULL);
}