Archive

Posts Tagged ‘c++’

Translating Instruction Address to Source Line

February 22nd, 2010

In this article I will describe how to programmatically translate an instruction address from a Win32 executable to a source line. The described approach uses the Microsoft debugger engine dbgeng.dll. Therefore you should have it installed. If you don’t have it, you can download and install the Windows debugger WinDbg which will install dbgeng.dll.

Requirements

To use this approach you will need to have installed windows debugger engine – dbgeng.dll. If you don’t have it, install WinDbg debugger. This will install dbgeng.dll

Approach

Many debuggers support debugging at source code level. The debugger is capable to provide debugging at the source level by translating instruction addresses to lines in source code files. In our approach we use the same mechanisms that debuggers use. This particular solution, to translate an instruction address to a source line, uses functionality provided by the windows debugger engine dbgeng.dll.

In overview, we create a process from the Win32 executable file from which we want to translate instruction addresses. Then we attach the debugger engine to the created process. To create a process and attach the debugger to it we use CreateProcessAndAttach function. When the debugger is attached, we call function GetLineByOffset to do the actual translation. After we finish with the translation task we terminate the process with the function TerminateCurrentProcess. Besides these procedures there are few more things that are necessary to do which I explain in the implementation.

Implementation

First we create objects that implement the following COM interfaces: IDebugControl , IDebugClient, IDebugSymbols. To create these objects we use function DebugCreate.

static IDebugClient5 *dbgClient5 = NULL;
static IDebugSymbols *dbgSymbols = NULL;
static IDebugControl *dbgControl = NULL;
...
DebugCreate(__uuidof(IDebugControl), (void**) & dbgControl);
DebugCreate(__uuidof(IDebugClient), (void **) & dbgClient5);
DebugCreate(__uuidof(IDebugSymbols), (void **) & dbgSymbols);

Before crating the process from the executable we set the debugger engine filters so that the target process breaks into the debugger immediately after it is created. To set the debugger filters we use function SetSpecificFilterParameters.

DEBUG_SPECIFIC_FILTER_PARAMETERS filter[10];
for (int i = 0; i < 10; i++) {
	filter[i].ExecutionOption = DEBUG_FILTER_BREAK;
	filter[i].ContinueOption = DEBUG_FILTER_GO_HANDLED;
	filter[i].TextSize = 0;
	filter[i].CommandSize = 0;
	filter[i].ArgumentSize = 0;
}

dbgControl->SetSpecificFilterParameters(0, 10, filter);

Using function CreateProcessAndAttach we create a windows debug process and attach the debugger to it.

ULONG64 server            = 0;
PSTR    commandLine       = executableName;
ULONG   processId         = 0;
ULONG   attachFlags       = 0; 

dbgClient5->CreateProcessAndAttach(
	server,
	commandLine,
	DEBUG_PROCESS,
	processId,
	attachFlags);

To translate the instruction address to a source line we call function GetLineByOffset.

ULONG64 offset = instrAddress;
ULONG fileNameBufferSize = MAX_FILE_NAME_SIZE;
memset(sourceInfo->fileName, 0, fileNameBufferSize);
sourceInfo->lineNo = 0;
sourceInfo->fileSize = 0;
sourceInfo->displacement = 0;

HRESULT isOk = dbgSymbols->GetLineByOffset(
	offset,
	&sourceInfo->lineNo,
	sourceInfo->fileName,
	fileNameBufferSize,
	&sourceInfo->fileSize,
	&sourceInfo->displacement);

If we want to translate multiple addresses, we have to call function GetLineByOffset multiple times without repeating the earlier operations. After we finish with the translation we detatch the debugger from the process by terminating the process with function TerminateCurrentProcess.

HRESULT isOk = dbgClient5->TerminateCurrentProcess();

Download

The code complete source code is available for download from InstructionToSourceLine.zip. Note that the instruction address provided as input should be a decimal number but not hexadecimal.

C# Version

There is also a C# implementation of this tool that you can download from InstructionToSourceLineCSharp.zip. This C# implementation consists of 2 parts – DbgEngManaged and InstructionToSourceLineCSharp. DbgEngManaged is a managed c++ library wrapper for the debugger engine DbgEng.dll. InstructionToSourceLineCSharp is a C# console application that references DbgEngManaged library. Note that the error handling here is not done properly so don't judge me for it :) The provided code here is something that I have quickly prototyped and decided to share for those who for some reason need to use the debugger engine. It can also serve as an example of using native and managed code together. 

Programming, windows , , , , , , , , , , , , ,

Uses of const in C++

May 25th, 2009

To exmplain to a friend the different uses and semantics of "const" in c++ I come accross one very nicely written article "The C++ ‘const’ Declaration: Why & How". It concludes with an example that has all the possible uses of "const" in one statement. I copy & paste it here.

Of course one sometimes needs to combine some of these different uses of ‘const’ which can get confusing as in

const int*const Method3(const int*const&)const;

where the 5 uses ‘const’ respectively mean that the variable pointed to by the returned pointer & the returned pointer itself won’t be alterable and that the method does not alter the variable pointed to by the given pointer, the given pointer itself & the object of which it is a method!

Programming ,

Uninitialized Variable May Waste a Whole Day

December 22nd, 2008

Today I was writing a program and implement I implemented a method that parses contents of a raw byte buffer into different primitive data types – including 32bit address and store them in 64bit unsigned integers.

Because I had two class member fields with similar names and I missed to initialize one of them to 0. Then when I copy the 32bit address from the buffer into the 64bit integer variable, my program was crashing like crazy and I didn’t have a clue that it could be because of the uninitialized field. I was checking if the 64bit variable is equal to the expected value (like in the code demonstrated below) but haaahh, it was not equal. And again, no idea why?!? So inspecting the code carefully and inserting stupid printfs around (ok I was not able to debug my application with a debugger) I could found the nasty uninitialized field at the end of the day at 01:20 midnight.

So here comes the lesson: Uninitialized variables are very dangerous and besides wasting your time may cause irreversible problems. It looks I should be thankful that my libraries were crashing and not hiding the bug.
Below I attach the code segment that is an example of the error I had today.

To compile: g++ -g -o UninitializedFieldCpp UninitializedFieldCpp.cpp

//————————————————————————-
//
// How I wasted a whole day because of uninitialized member field in C++.
//
//————————————————————————-

//#include “stdafx.h”

#include
#include

using namespace std;

typedef unsigned long long ULONG64;
typedef unsigned int ULONG;
typedef unsigned char byte;

//
// Here we have 16 bytes
//
byte buffer[] = {0×00, 0×00, 0×00, 0×00, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0×00, 0×00, 0×00, 0×00};

class MyClass
{
public:
MyClass():_initializedField(0) {}

void copyNumberUninitializedField()
{
//
// Here we get a pointer to the first FF byte in the buffer
//
byte* pointerToFF = buffer + 4;

memcpy(&_uninitializedField, pointerToFF, sizeof(ULONG));

if (_uninitializedField == 0xffffffff)
{
cout << “_uninitializedField: there is no problem” << endl;
}
else
{
cout << “ERROR: ” << endl;
cout << “_uninitializedField must be equal to 0xffffffff, but was: “;
cout << hex << _uninitializedField << endl;
}
}

void copyNumberInitializedField()
{
//
// Here we get a pointer to the first FF byte in the buffer
//
byte* pointerToFF = buffer + 4;

memcpy(&_initializedField, pointerToFF, sizeof(ULONG));

if (_initializedField == 0xffffffff)
{
cout << “_initializedField: there is no problem” << endl;
}
else
{
cout << “ERROR: ” << endl;
cout << “_initializedField must be equal to 0xffffffff, but was: “;
cout << hex << _initializedField << endl;
}
}

private:
//
// This is our uninitialized field.
//
ULONG64 _uninitializedField;

//
// This is our good initialized field
//
ULONG64 _initializedField;
};

int main(int argc, char* argv[])
{
MyClass m = MyClass();

m.copyNumberUninitializedField();

cout << endl << endl;

m.copyNumberInitializedField();

cout << “Done” << endl;

return 0;
}

Programming , ,