Archive for October, 2008
I have always freely admitted that Win32 development is not my thing. What started as a religious conviction (UNIX being what it was when I was a lad…) and later became first a lack of opportunity and exposure and most recently a conscious choice to keep my skills marketable in niche markets, I’ve just done very little work on the platform. Sure, during the heyday of Windows CE (now Windows Mobile) I learned enough to talk with skilled Win32 developers transitioning to Windows CE, and successfully managed WinCE-based development projects, but that’s not engineering. More recently, I wrote a book on developing applications for eBay that included examples in C#, but that’s different. C# is managed code, and anyway, writing still isn’t really engineering.
Nonetheless, much of my career has been spent working within the confines of the Win32 platform. Many mobile platforms such as Qualcomm BREW stage their development environments on top of Win32, providing emulators in which the application you’re writing is linked in as a Win32 DLL. While this has its limitations—emulation isn’t simulation, etc—it’s definitely a good way to go for platform vendors, because the Win32 tool chain is well-understood by countless developers, even if the intricacies of a specific mobile platform isn’t.
At the day job, I recently came across a need to track down a number of memory leaks in a C-based application for Qualcomm BREW. The code had already been written, so it wasn’t feasible to go back and implement a wrapper to the memory management utilities that tracked allocation and free operations using the __FILE__ and __LINE__ macros; even if I could, I also needed to track down a few BREW component instance leaks, which would be considerably more complex to track using wrappers. Because of the need to determine component instance leaks and how the BREW simulator manages its own heap (providing leak reporting, at least), tools like Purify weren’t really an option either.
By hand-editing the include files that define BREW’s object creation and memory allocation routines (AEEShell.h and StdLib.h) I could directly hook the memory allocations, giving me an opportunity to determine the source of the leaks…if only I knew what portions of the code were performing the allocations. Using a dictionary matching pointers to memory or components and information about how those regions re allocated isn’t my idea; it’s hardly new, and frankly, I don’t know where it originated. It is a good idea, though, because it makes the work go a lot faster. By instrumenting allocations to track where in the code the allocation is being made (typically inserting that information in a dictionary keyed by the pointer to the region or component being allocated) and instrumenting the deallocation to release those records, an examination of the resulting dictionary after a run gives you a list of points in your code that may be allocating resources that aren’t freed later. The technique isn’t perfect, of course, especially if you pass references to memory or components around to other systems that you can’t instrument, but it’s a good start. I had a dictionary implementation that I could use to store information about each allocation referenced by pointer; if I could get stack frame data at the points where I hooked the allocator and deallocators, the work would become much easier.
I knew that I should be able to programmatically get stack trace information running under the simulator on Win32, although I had no idea how. Oddly, this doesn’t seem to be common knowledge, either, after pinging a few colleagues on the subject. However, after more reading of MSDN articles and googling than I care to admit, I came across Jochen Kalmbach’s StackWalker class, a C++ class that provides an utterly simple interface to obtain a stack crawl anywhere in your Win32 application. Great stuff, and I’m glad I found it! Using it was far simpler for me than trying to wrap my head (and some new code) around the debugger API that Microsoft provides.
I was quickly able to modify it to meet our needs to run within the Qualcomm BREW simulator and provide stack dumps to a log file; after those changes and a bit of truly shameless hacking on private copies of AEEStdlib.h and AEEShell.h, leak tracking became much easier. At some point I plan on providing a simple BREW component for simulator-only use that incorporates his code and provides much of the same functionality; it may make a good article or blog post in the future. In the mean time, I hope that simply describing the process here helps someone.
This experience provides a situation supporting my belief that a general interest in computing and computing platforms is key to being a good software engineer; if I’d thought too narrowly about the problem as being inherent to an application running on Qualcomm BREW, I might never have decided to add a bit of simulation-specific code to automate the bookkeeping behind my debugging.