Code for Concinnity


“Pretty-printing” STL vector in Eclipse CDT

It’s surprising to see why the C++ debugging scene in Mac/Linux is so behind Visual Studio. One definite strengths of MSVS is the ability to display STL vectors as arrays in the debug view.

If you’re using Eclipse CDT on Mac, you’re probably stuck with GDB 6.8 which doesn’t come with pretty printing. I tried self building GDB 7.2 but Eclipse CDT 8.0 doesn’t seem to be able to interact well with it (please someone come and correct me if I’m wrong).

So here’s how to display std::vector nicely even if you’re using GDB 6.8:

As you can see, the trick is to convert it to a pointer and to use the array syntax *((int*)nums) @ 3

Enjoy :)

Published by kizzx2, on July 3rd, 2011 at 12:37 pm. Filled under: Useful tips Tags: 3 Comments

Tutorial: Using WinDBG to call arbitrary functions — WinDBG kung-fu series

Most people developing for MS would praise how MSVS debugger is the best debugger out there (I doubt if many of them have actually used any other debuggers when they say that). That may be true for managed code debugging (.NET), but I just find that MSVS feels severely crippled when it comes to hard-core low level stuffs in C/C++.

This example shows you how to use the better tool for the job — WinDBG. While still severely crippled compared to GDB+Python scripting. Anyway…

The example program

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
#include <string>

class foo
{
public:
    foo(const char * name)
    {
        this->name = std::string(name);
    }

    void speak()
    {
        std::cout << "Hello, my name is " << name << std::endl;
    }

private:
    std::string name;
};

int main()
{
    foo * fred = new foo("fred");
    fred->speak();
    delete fred;
    return 0;
}

Our objectives

Have the output say “Hello, my name is chris” by creating a new foo object on the fly.

Now the action

Starting up…

1
2
> cl /EHsc /Zi /Fefoo.exe /Fdfoo.pdb foo.cpp
> windbg foo.exe
1
0:000> bm main; g

F10 a few times to stop at the line fred->speak().

The first command we’ll introduce is .dvalloc. We can allocate memory on the heap in the process’ address space.

Since foo::foo needs a string, we’ll first create a string.

1
2
3
0:000> * just put some arbitrary size
0:000> .dvalloc 100
Allocated 1000 bytes starting at 00150000

You’ll notice that we got allocated 1000 bytes instead of 100 as we asked. That’s OK. They just like to give us whole pages.

Now we’ll put some string in that memory address

1
0:000> eza 0x150000 "chris"

Now we’ll call foo::foo. All member methods have an implicit first parameter that should be this. Compiler usually inject that for us, but here we need to specify it.

Now we’ll allocate some space for our foo. This time around we’ll use malloc

1
2
3
4
5
6
7
8
9
0:000> .call malloc(100); g
Thread is set up for call, 'g' will execute.
WARNING: This can have serious side-effects,
including deadlocks and corruption of the debuggee.
.call returns:
void * 0x00c21310

foo!main+0x6b:
0126145b 8b4df0          mov     ecx,dword ptr [ebp-10h] ss:002b:0032fe2c=00c21258

The thing about malloc is that we can get the return value nicely stored in a pseudo-register $callret. I usually prefer that to .dvalloc. Having the return value in $callret aids a lot in scripting WinDBG. We’ll not touch on that to not make things too difficult.

Now onto creating the foo object:

1
2
3
4
5
6
7
0:000> * recall these addresses we allocated before
0:000>.call foo::foo(0x21310, 0x150000); g
Thread is set up for call, 'g' will execute.
WARNING: This can have serious side-effects,
including deadlocks and corruption of the debuggee.
foo!main+0x6b:
0126145b 8b4df0          mov     ecx,dword ptr [ebp-10h] ss:002b:0032fe2c=00c21258

Great, the final touch is to swap out fred with our newly created object.

1
2
0:000>ep @@(&fred) 0x21310
0:000>g

Cool! You should get “Hello, my name is chris”


If you came here searching for “WinDBG call function” or something like that, you’ve probably came across this post on The Old New Thing. That one is more advanced than what we have here :P Probably this will serve as a gentler introduction.

Published by kizzx2, on October 26th, 2010 at 11:29 pm. Filled under: Useful tips Tags: No Comments

Detecting memory leaks with WinDBG the modern (and free) way

This information is surprisingly scarce on the Internet. I should have realized earlier that the world has simply moved on to more modern languages than those who tax us to deal with mundane things like memory leaks.

Anyway, for those who’re still stuck, this should be your savior. This is almost as good as Valgrind on nix

Minimal example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    #include <crtdbg.h>

    void leak()
    {
        ::operator new(1000);
        new double[1000];
    }

    int main()
    {
        _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
        leak();

        return 0;
    }

Running the above code will get you something like this in the Debug output:

Detected memory leaks!
Dumping objects ->
{67} normal block at 0x00573FC8, 8000 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 
{66} normal block at 0x005713E8, 1000 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 
Object dump complete.

This is nice and good, but it isn’t very useful since we (pretend) don’t know where the leak came from!

And then WinDBG comes in

(Obviously, add WinDBG to your PATH first)

First, we’ll turn on heap stack tracing for our program. gflags.exe needs to be run with elevated privileges:

1
    > gflags /i leak.exe +ust

Now we’re ready to go!

1
    > windbg -g leak.exe

At the debug output in WinDBG, we’ll see our leak report:

Detected memory leaks!
Dumping objects ->
{80} normal block at 0x003B4378, 8000 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 
{79} normal block at 0x003B3F50, 1000 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 
Object dump complete.

At WinDBG, we can trace down the originating functions

000:0> !heap -p -a 0x003B4378

address 004b4378 found in
_HEAP @ 4b0000
  HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
    004b4340 03f0 0000  [00]   004b4358    01f64 - (busy)
    Trace: cfba8
    7753dd4d ntdll!RtlAllocateHeap+0x00000274
    6fa87743 MSVCR100D!_heap_alloc_base+0x00000053
    6fa95d8c MSVCR100D!_heap_alloc_dbg_impl+0x000001fc
    6fa95b2f MSVCR100D!_nh_malloc_dbg_impl+0x0000001f
    6fa95adc MSVCR100D!_nh_malloc_dbg+0x0000002c
    6fa9906b MSVCR100D!malloc+0x0000001b
    6fa871b1 MSVCR100D!operator new+0x00000011
    6fa872ef MSVCR100D!operator new[]+0x0000000f

    dc13d5 leak!leak+0x00000035

    dc1447 leak!main+0x00000037
    dc19df leak!__tmainCRTStartup+0x000001bf
    dc180f leak!mainCRTStartup+0x0000000f
    75f43677 kernel32!BaseThreadInitThunk+0x0000000e
    774f9d42 ntdll!__RtlUserThreadStart+0x00000070
    774f9d15 ntdll!_RtlUserThreadStart+0x0000001b 

There you go! The highlighted line above is the culprit. For those unfamiliar with WinDBG, here’s a little more hand holding: Click on the source code view, Ctrl+G and then type leak+0x35.

Remember to turn gflags off afterwards. The gflags is a registry and won’t clear even if you delete the file itself.

1
    > gflags /i leak.exe -ust

32/64 bit

To debug 32 bit applications in a 64 bit system, you need to use the 32 bit version of WinDBG, which is not installed by default. You can find dbg_x86_*.msi somewhere in your “Microsoft SDKs” installation directory.

More advanced usage

Heap debugging is not restricted to detecting leaks. If you find your application allocating a lot of memory in some places, you can easily trace down where they come from with WinDBG and the !heap extension. This CodeProject article describes how to do just that in depth.

However, for doing that, I find a more modern and less intrusive way to be using XPerf tool. That combined with WinDBG and you’ve got a debugging power-house. (Resources on how to do it is extremely scarce. If you thought this WinDBG technique is obscure, you ain’t seen nothing :p I may write an post about that some time later when I feel like it.)

Wrong way of doing it

MSDN suggests something like this

1
2
3
4
5
6
    #define _CRTDBG_MAP_ALLOC
    #include <stdlib.h>
    #include <crtdbg.h>

    // At the end of your program
    _CrtDumpMemoryLeaks();

This solution is inadequate for a couple of reasons:

  • It only lists source code location for malloc. What’s the point?
  • Calling _CrtDumpMemoryLeaks() at the end of main() would mistakenly report memory allocated by static objects as leaks.

The only good thing about it is that you don’t need to leave your comfort zone of Visual Studio (that’s probably the entire programmer life for many people, unfortunately).

Some other good resources

Published by kizzx2, on October 9th, 2010 at 12:36 am. Filled under: Useful tips Tags: , , , , No Comments

Cygwin slow start up: the culprit discovered!

If you’ve found the start-up time of Cygwin slowing down significantly after you’ve upgraded from 1.5 to 1.7, here’s a one liner to improve it around 500%:

1
$ mv /etc/profile.d/bash_completion.sh{,.disabled}

The bash_completion is apparently undergoing some massive restructure. The fact that fork is very inefficient on Windows (Windows’ inferior process model can’t really handle that, Cygwin did a great job mimicking it) make it not really ready for prime time on Cygwin.

You can still get bash_completion manually if you need it:

1
$ . /etc/bash_completion
Published by kizzx2, on September 7th, 2010 at 11:33 pm. Filled under: Useful tips Tags: 22 Comments

Iterating Bash arrays with spaces

The problem

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/bin/sh

$ a=(hello world foo bar)
$ for i in #{a[*]}; do echo $i; done

# Expected output:
#   hello
#   world
#   foo
#   bar

# so far so good:
#   hello
#   world
#   foo
#   bar

$ a=("hello world" "foo bar")
$ for i in #{a[*]}; do echo $i; done

# Expected output:
#   hello world
#   foo bar

# omg:
#   hello
#   world
#   foo
#   bar

The problem is caused by the affect that Bash uses space as array element separator internally.

Failed attempt

1
2
3
4
5
6
7
8
9
10
11
#!/bin/sh

$ a=("hello world" "foo bar")
$ for i in "#{a[*]}"; do echo $i; done

# Expected output:
#   hello world
#   foo bar

# zomg!
#   hello world foo bar

The solution

The solution lies in the magical $@ expansion. When the $@ expansion is put in a quote, the shell automatically expands each element properly quoted:

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/sh

a=("hello world" "foo bar")
for i in "#{a[@]}"; do echo $i; done

# Expected output:
#   hello world
#   foo bar

# yay!
#   hello world
#   foo bar
Published by kizzx2, on April 10th, 2010 at 1:27 am. Filled under: Useful tips Tags: , , , 2 Comments

Muxing audio and video with ffmpeg

ffmpeg is a great codec converter, but it’s wide array of options is really daunting. I just figured out it can also be used to mux video and audio together into a file, here’s how to do it

1
2
3
4
5
6
7
8
9
10
# Simple example: mux an audio with a video file without audio track
$ ffmpeg -i audio.mp3 -i video.avi -acodec copy -vcodec copy output.avi

# Daily usage example: mux an audio with a video file _with_ an existing audio track.
# This will replace the AVI file's audio track with the MP3
$ ffmpeg -i audio.mp3 -i video-with-audio.avi -acodec copy -vcodec copy output.avi -map 0.0 -map 1.0

# krrrrrz from the comments says that this is the new syntax
# (-map before other parameters)
$ ffmpeg -i audio.mp3 -i video-with-audio.avi -map 0.0 -map 1.0 -acodec copy -vcodec copy output.avi

The key to the second command is the -map parameter. Typically, the output file would contain two streams: one audio and one video. The numbers 0.0 and 1.0 refers to the first input file and the second input file respectively.

The -map parameter is used to spell out the streams. What the above said was “use input stream 0.0 for your first output stream (which is an audio stream) and input stream 1.0 for your second output stream (which is the video stream)”.

You can see a list of stream numbers by

1
$ ffmpeg -i audio.mp3 -i video-with-audio.avi

You can add additional streams to the output file with the -newaudio and -newvideo parameters. Two audio streams make sense when you’re making a DVD rip with two sound tracks. I didn’t try it myself but it’s nice to know :P

Cheers :)

Published by kizzx2, on April 8th, 2010 at 6:10 pm. Filled under: Useful tips Tags: , , 10 Comments

Vrapper: open source vim plugin for eclipse

Found out Vrapper recently. The fact that it is open source deserves a lot of merits. For years eclipse users only had the commercial option ViPlugin which didn’t work quite well for something that charges money, considering the NetBeans folks have the excellent jVi which is also open source.

Considering eclipse is free and open source, Vrapper only seems more fitting than ViPlugin. I’ve tried it for a week and it seems most essential functions are there, and I’ve been using vi for a couple of years so I think my set of “essential functions” shouldn’t be too narrow :p

Published by kizzx2, on April 8th, 2010 at 5:49 pm. Filled under: Useful tips Tags: , , , , , No Comments

Installing HuffYUV on Windows 7 x64

This will probably also apply to other INF based installation for that matter. A simple command line saved me hours of trouble:

rundll32 C:\Windows\SysWOW64\setupapi.dll,InstallHinfSection DefaultInstall 0 C:\Path\To\huffyuv.inf

Run the above with admin privilege and bam, HuffYUV correctly appears in my codec list.

P.S. If you’re looking for a lossless codec, maybe take a look at Lagarith. It claims to be an improvement to HuffYUV and supports multi-processor encoding. It also comes with a dedicated installer so there’s no need to tinker with the command line just to install the codec.

Published by kizzx2, on April 5th, 2010 at 6:18 pm. Filled under: Useful tips Tags: , , , , 12 Comments

cmd-recycle: Delete files from Windows command line

Download links

I wrote another tool to do just this a while ago, but that one stopped working since I migrated to Windows 7 x64. Microsoft said the SHFileOpearation interface (which the old tool used) had been replaced by the IFileOperation interface. So I figured I would dig up my rusty C# again to update it.

Damn, I can’t believe it took a couple of hours, but the result worked amazingly. This one also supports wildcards:

1
recycle file1 file2 supports-wildcards\*.tmp

I’ve gone the extra mile and set up a proper repository this time around on GitHub. Probably some Windows gurus will mock me left and right with some obscure one-liners or something, lol.

Published by kizzx2, on January 6th, 2010 at 3:30 am. Filled under: Useful tips Tags: , , 2 Comments

Starting Windows’ Network and Sharing Center from command prompt

It has always looked not-so-cool to have to type “Sharing” at the start menu or worse yet, navigate through the Control Panel just to start it. Today I finally dug out how to do it from TechNet:

1
control /name Microsoft.NetworkAndSharingCenter

Looks like Microsoft decided to go down the verbose path. Maybe I’ll just stick with the old ways :p

Published by kizzx2, on December 29th, 2009 at 9:21 pm. Filled under: Useful tips Tags: , , , No Comments