Blog gone, google+ instead

There hasn't been many posts here the last year or so. The main reason is that I'm spending more time on social networks now, and time is limited!

Anyway, I think Google+ combines blogging and social networking in a good way, so I'm basically closing this blog now. My Google+ page is being updated though, and contains much of the stuff that I used to write about here.

Promenadstad - Pedalstad

Jag har precis kommit tillbaka från en tågresa till Frankrike som gick via Tyskland och Nederländerna. Syftet med resan var cykelsemester i Loire, men det jag tänkte tala om här är Amsterdam... och Stockholm. Jag fick nämligen upp ögonen för vissa saker i Amsterdam, en slags vision kan man kalla det, och det alldeles utan att provröka deras specialcigaretter.

Såhär tror jag nämligen det är: Stockholms stadshusmajoritets vision om promenadstaden behöver i själva verket bli pedalstaden. Amsterdam är nämligen en alldeles utmärkt promenadstad, och det tror jag beror på att man satsar stenhårt på cykeltrafiken. Vi hyrde cyklar och provade på cykeltrafiken i Amsterdam, och här är några observationer på allt positivt de lyckats med:


  • Bil- och cykeltrafiken är inte separerad.

    Amsterdam satsar på cykeltrafik, men utan att för den delen förbjuda biltrafik. Bilar och cyklar delar på gatuutrymmet, men i cyklarnas tempo. I början väjde vi undan när en bil närmade sig bakifrån, som man gärna gör i Stockholm, men i Amsterdam försökte aldrig bilarna köra om, så ganska snart var man van och cyklade på som vanligt.

    I Stockholm anlägger man istället gärna supersmala cykelremsor, och cykelbanelagen förbjuder cyklister att använda gatan. Snacka om snedprioritering.

  • Trafiken är anpassad till cyklarnas tempo.

    Jag tänkte inte på hastighetsbegränsningar längs gatorna (överhuvudtaget var det få skyltar), men trafiken går i praktiken i cykeltempo. Förutom de uppenbara fördelarna för cyklister så gynnar det även fotgängare och gatuliv: bilar bullrar avsevärt värre i 50 km/h än 20-30. Att sitta på uteservering längs gatorna i Amsterdam är ett tyst och skönt nöje, något man knappast kan säga om Stockholm.

    Hur kul är det med promenadstad längs bullergator?

  • Cyklar får köra mot enkelriktat.

    Cyklister i Amsterdam får köra mot enkelriktat som regel (undantag finns troligtvis). I det lugna trafiktempot är detta ingen säkerhetsrisk och det ökar förstås avsevärt framkomligheten.

  • Inga kantstenar.

    I Stockholm är gång- och cykelbanan (där det finns en separat) ofta separerade med hårda kantstenar. Kör man på en sådan faller man hårt. I Amsterdam däremot har man på de flesta ställen rundade stolpar som man kan åka mellan om man behöver stanna. Superenkelt och supersmart.

  • Cykelbanor är rödmarkerade.

    Även i Stockholm markerar man cykelbanor med avvikande färg. Efter någon säsong är färgen borta och omöjlig att se. I Amsterdam använder man istället rödfärgade plattor eller röd asfalt som markerar cykelbanor (och gememsamma bil- och cykelgator). Mycket smartare.



Amsterdam Bicycle Lane

Så sammantaget fick jag mycket positiva upplevelser i Amsterdam, och jag önskar att Stockholm kunde närma sig Amsterdam. Helt enkelt tycker jag översiktsplanen skulle fokusera på att bygga pedalstaden, så får man en promenadstad på köpet. Så frågan är hur man fixar till detta? Jag är ju knappast någon expert på området, men några saker tror jag är:
  • Förtätning.

    Just detta finns ju faktiskt med i översiktsplanen, så här går det åt rätt håll. Det är egentligen ganska enkelt: Tät stad lämpar sig för cykling, kollektivtrafik och promenad, gles stad blir bilberoende. Gatuliv får man på köpet med en tät stad.

  • Sänk hastigheten för trafiken.

    I innerstaden och närförort tycker jag 30km/h skulle vara den normala hastighetsgränsen. I denna hastighet kan cyklister och bilister samsas om samma gator mycket enklare, och i praktiken förlorar knappast bilisterna någon tid på det heller. Precis som i Amsterdam blir ju också gatulivet mycket trevligare om man slipper bilbullret.

  • Infartsparkeringar.

    Med tunnelbanan har Stockholm bättre kollektivtrafik än Amsterdam (eller borde kunna ha). Lite infartsparkeringar vid strategiska punkter tillsammans med högre trängselskatt skulle säkert få bort en del av biltrafiken och öka framkomligheten för cyklister.

  • Cykling mot enkelriktat.

    Med 30-gräns på enkelriktade gator borde det vara enkelt att tillåta cykeltrafik mot körriktningen. Det finns ju redan nu här och där, men längs separerade cykelbanor.

  • "Bicycle superhighways".

    "Cykelmotorvägar" som den mellan Malmö-Lund Karin Svensson-Smith föreslagit skulle avsevärt underlätta långpendling via cykel. Vi cyklade till Vaxholm för någon månad sedan, och jag kan intyga att det inte är någon höjdare att cykla på en smal vägren längs 90-väg.

    Så rejält snabba cykelhighways till förorterna hade verkligen gjort tillvaron drägligare.


Cykel heter för övrigt Fiets på holländska!

(no subject)

I've finally put together a new Cibyl release! To recap, Cibyl is a programming environment and binary translator which translates MIPS binaries into Java bytecode. In effect, in enables C/C++ programs to be ported to pure-Java environments such as J2ME and blackberry phones.



The release contains many new features in version 21, of which these are the most important:
  • There are now binary releases of the SDK, complete with toolchain, both for Linux and for Windows (cygwin). This should make it much easier to use than before.

  • The cibyl environment is globally installable now, so you can copy it to e.g., /usr/local/ if you wish

  • Major optimization improvements: DWARF debugging information is used to reduce function call overhead

  • Minor optimization improvements: better peephole optimization, instruction improvements, better memset/memcpy implementations (all by Marcus Groeber)

  • The build-system has been completely rewritten, and is now cmake-based and much better than before

  • Various bug fixes and code cleanup



Get the release from cibyl.org, and the source code at github!

Lots of thanks to Marcus Groeber, who contributed the Windows build and a lot of optimization improvemenets and bug fixes, as well as Maik Merten and Ehud Shabtai for various bugfixes and improvements.

MPD + Despotify + MCI500h = music

I'm finally getting somewhere with the rooted MCi500h. After initially having based the development environment on buildroot, I never managed to get networking running. Instead, I switched to a Debian Etch-based distribution, which runs fine with the old 2.4.27 kernel.

I also got the source code for the kernel from Philips, which helps a bit with how to use the system. Looking at their patches (which I've uploaded to github), you can see that they violate the kernel conventions in many places with a lot of magic IOCTLs, special hacks and ugly workarounds. Well, well. I don't intend to replace the kernel anyway.


Anyway, my long-term plan is the following:
  • A Debian-based distribution which you can install stuff as you want in

  • The Music Player Daemon to playback music. MPD provides lots of nice features and supports basically all major music formats. It also has very good client support.

  • A web server with a web-based MPD client

  • Spotify-support via Despotify through MPD

  • A MPD-client running on the built-in display and controlled via the remote

  • FM radio support etc

And so far, I've written a set of patches for Despotify to enable libtremor support for integer decoding (the MCI500h ARM is FPU-less). For MPD, I've added Despotify input/playlist plugins and fixes a few bugs which I stumbed upon. The "distribution" and a set of tools is also found in a repository at github. So I've built a binary release for testing which can be downloaded from googlecode.

Left to do is basically the interface stuff plus adapting to the Philips-specific hacks. For example, volume control is done via (I think) i2c (naturally, not using the kernel driver interface but an IOCTL-based one). This will be quite a bit of work, but at least there is something to base the rest on now.

New Kcov and Dissy releases

I'm the main developer of a number of small projects: Cibyl, Kcov, Dissy as well as a few others. I do releases sometimes, but often features are hidden in the development trunk for a long time. Releases are simply boring to do and doesn't actually bring anything for me personally :-)

However, this weekend, I've finally put out new releases of two of my projects: Kcov and Dissy. Kcov, first, is a code coverage tool which uses DWARF debugging information to instrument the executable with breakpoints (it's based on bcov):



The new release, version 5, improves usability a bit by allowing filtering by both paths and patterns (previously only patterns), and has a lot of internal changes which doesn't show outside of the source code. Download from github.

The second project, Dissy, is a graphical frontend to the objdump disassembler. I use it myself pretty much daily, so I think it's the most useful of the things I've written.



Dissy version 10 has many improvements: The workspace can be saved and reloaded later, instructions can be commented, the window size is remembered on restart and more branch instructions are recognized. A number of bugs have also been fixed. Download from googlecode.


Thanks to the contributors to both projects!

More work on the MCi500h

In the last post, I wrote about rooting the Philips MCI500h stereo. The question was what to do with it. Well, what I started looking at is a combination of one or more of despotify, MPD, the music player daemon and Rockbox. You might wonder how all that went.


I've made some progress, but got stuck on a slightly tricky and irritating issue. I setup a buildroot-based enviroment for building my own rootfs, and started looking at despotify. After some initial troubles, I've managed to build a version that actually starts on the MCI500h. However: There is no network access, either from despotify or from the busybox command line tools. I believe this is an issue with the aging kernel (2.4.27) and the newer uClibc I used when building the rootfs. The problems look like this:
g2 trunk 6869 Island:# nslookup www.dn.se
Server:    192.168.1.1
Address 1: 192.168.1.1

nslookup: can't resolve 'www.dn.se'
g2 trunk 6869 Island:# ping 192.168.1.104
PING 192.168.1.104 (192.168.1.104): 56 data bytes
ping: can't create raw socket: Function not implemented
g2 trunk 6869 Island:# telnet 192.168.1.104
telnet: socket: Function not implemented

and obviously neither despotify nor MPD are very interesting without network support.

I did verify that OGG Vorbis plays on the device though. libvorbis uses floating point and is much too slow for the processor to decode, but using the tremor integer-only decoder, it plays fine from mplayer. This leads me to believe that despotify should be possible once the networking issue is solved. I've also built despotify against tremor and verified that on the host.


So how does one continue? Well, I'd urge other interested developers to take a look at this - I've setup a few git repositories on github. What I plan to test is to build with other C libraries. Eglibc is an obvious possibility, at least if it's possible to swap in the existing (old) glibc libraries instead of it. Newlib might be an alternative as well, although I'm not sure if it's possible to build all tools using that. I've also tried to build uClibc and the other tools using the old 2.4.27 kernel. I've made some progress there, uClibc builds but busybox fails because of the old kernel. This path unfortunately requires some ugly hacks for buildroot, so it might not be feasible in the end.

Finally, I've requested the GPLed source code from Philips. I've still heard nothing from them, but I hope they'll realise that they are legally obliged to send me the sources.

Rooting the Philips MCI500h micro stereo

This entry describes how to get a root shell on your Philips MCI500h micro stereo, with a few easy steps. Basically, what we need to do is to enable SSH and then SSH into it. There are three, very simple steps to do this:
  • Set the dbg_startsshd NVRAM parameter to true

  • Reboot the MCI500h

  • Login via SSH



The Philips NVRAM daemon listens to port 6481, which conveniently is a web interface. Just pointing your browser to that port will give you a list of the current NVRAM contents. What we want to do is to set dbg_startsshd to true, which we can do via the web interface like this:

In your web browser, go to http://[your-mci500h-ip]:6481/dbg_startsshd?true , and you should see a screen with OK. If you reload http://[your-mci500h-ip]:6481 in your browser, you will see the new setting.

Then reboot your stereo. It's not enough to press the power button, but unplugging it should do the trick, or telnetting to port 10023 and running the # command. After the stereo has booted up, ssh will be enabled and you should be able to ssh to it like below:
  ska@x41:~$ ssh root@192.168.1.129
  root@192.168.1.129's password: 
  Welcome to NXP Semiconductors PNX8706 Linux !!


  BusyBox v1.2.1 (2010.01.21-08:20+0000) Built-in shell (ash)
  Enter 'help' for a list of built-in commands.

  g2 trunk 6869 Island:# ls
  blob1.bin       wl.o            wl_recovery.ko
  g2 trunk 6869 Island:# uname -a
  Linux pnx0106 2.4.27-vrs1-6869 #1 Thu Jan 21 16:16:41 CST 2010 armv5EJl unknown
The root password is root, which I managed to guess the first time :-)


A few words about how I found this out as well. Well, I first downloaded the firmware image. This is a CRAMFS filesystem image, which can be uncompressed as described here.

Looking around in that image, I started looking in /etc/ and /usr/local, where the Philips-specific stuff is located. Seeing that /etc/init.d/rcS contained this line:
  [ "$(/usr/local/bin/nvram get dbg_startsshd)" = "true" -a -x /usr/bin/dropbear ] && \
  { echo "Starting dropbear SSH server...";
it was fairly easy to run strings on /usr/local/bin/nvramd and find these interesting strings:
  GET / SIMPLE
  GET /%s SIMPLE
  usage: nvram [get name] [set name=value] [unset name] [show]
  GET /%s?%s SIMPLE
  unset
  GET /%s? SIMPLE
  show
And after some poking, I found out how to set the NVRAM values. The password was easy to guess, thanks for that Philips :-)


So now that we've got root, what are we going to do with it?

Update: Instead of telnetting to 6481, just pass the new NVRAM variable via the web browser.

Cibyl and usability - now improved!

In the emails I get about Cibyl, a common theme is problems with getting the environment setup. Especially getting a MIPS cross compiler to your system is more difficult than it might seem a first. Cibyl itself is also not really for the faint-hearted, especially for people that use Windows and other systems (which I never test on).

So making Cibyl a bit simpler to use is something I should have done a long time ago, but finally got round to doing now. What I wanted to get rid of was this eye-sore when running make in the hello-world example:
  mips-linux-gcc -G0 -DCIBYL=1 -ggdb -msoft-float -fno-optimize-sibling-calls -nostdinc -Wall -Wa,--no-warn\
   -mips1 -mno-check-zero-division -Os -fno-pic -mno-abicalls -I/home/ska/projects/cibyl/old/cibyl/include \
   -I/home/ska/projects/cibyl/old/cibyl/include/generated -I.   -c main.c -o main.o
  main.c: In function 'main':
  main.c:26: warning: unused variable 'v2'
  mips-linux-ld -L/home/ska/projects/cibyl/old/cibyl/libs/lib/ -EB -nostdlib --whole-archive --emit-relocs main.o\
   /home/ska/projects/cibyl/old/cibyl/libs/crt0.o -T/home/ska/projects/cibyl/old/cibyl/build/linker.lds\
   --start-group -lcrt0  -lc -ljava --end-group -o program
  make[1]: Leaving directory `/home/ska/projects/cibyl/old/cibyl/examples/host-java/hello-world/c'
  install -d res
  install -d tmpclasses
  install -d classes
  touch .dirs
  /home/ska/projects/cibyl/old/cibyl/tools/cibyl-mips2java -DNOJ2ME -d tmpclasses\
   -I/home/ska/projects/cibyl/old/cibyl/include/generated c/program
  cp tmpclasses/program.data.bin res/program.data.bin
  cp /home/ska/projects/cibyl/old/cibyl/java/StandaloneMain.java tmpclasses/StandaloneMain.java
  cp /home/ska/projects/cibyl/old/cibyl/java/CRunTime.java tmpclasses/CRunTime.java
  cp /home/ska/projects/cibyl/old/cibyl/java/CibylConfig.java tmpclasses/CibylConfig.java
  cd tmpclasses && /usr/lib/jvm/java-6-sun//bin//javac -classpath :  *.java
  Note: CRunTime.java uses unchecked or unsafe operations.
  Note: Recompile with -Xlint:unchecked for details.
  touch tmpclasses/.rebuilt
  cp tmpclasses/*.class classes/
  touch classes/.rebuilt
A fairly good amount of ugly steps, right? Well, with the current GIT head, it looks like this instead:
  mips-cibyl-elf-gcc -Os -o program main.c
  cibyl-mips2java -d tmpclasses -DNOJ2ME program
  Generated: tmpclasses/Cibyl.class
  Generated: tmpclasses/Cibyl1.class
  cp `cibyl-config --sysroot`/usr/share/java/StandaloneMain.java tmpclasses
  cd tmpclasses && javac -source 1.4 *.java
  cd tmpclasses && jar cfm ../program.jar ../manifest.txt *.class program.data.bin
which is much better in my opinion. Here you actually have a chance of spotting warnings and errors in the output, and there are fewer steps. Also, the confusing extra options to GCC (which are there to generate more Cibyl-friendly code) are gone and the Java runtime system is installed automatically. The list of improvements is basically:
  • A crosstool-ng-built 4.4.5 toolchain. Newer than the old ELDK 4.0 toolchain, should be a bit better optimized.

  • The cibyl tools (cibyl-mips2java among others) are now installed alongside the toolchain.

  • The cibyl libs etc are installed in the toolchain sys-root, so as long as the cibyl tools can be found in the PATH, the location of the cibyl libraries and header files are also known.

  • I've switched the build system to cmake. Improves depedency handling a lot, but was a bit painful to get used to.

  • Similar to how e.g., SDL works, I've added a cibyl-config tool which can be used to get default directory paths etc

  • A few bugs in the DWARF-based function optimization have been fixed

I looked at setting up the toolchain with default compiler arguments and the Cibyl linker script built-in, but I couldn't get g++ to work then. So it now builds a defualt MIPS compiler and then with symlinks and small scripts, the arguments are tacked on.

It's probably time to release a new Cibyl version soon, and I intend to make binary releases in addition to the source tarball. Hopefully, even a windows binary release should be possible although someone else will have to build that.

Cibyl: improving register passing using DWARF information

In the last post I wrote about how to retrieve information on function arguments and return values using DWARF debugging information. You might now wonder what that was all about, but no worries: I'll explain everything in this post. Some of you might already have guessed that it's related to Cibyl, my binary translator. The main issue at hand is this:
  • Translated C function calls are expensive to make in Java
and the rest of the post will explain the problem and a way of improving that situation. First, since Cibyl translates MIPS binaries into java bytecode, we'll need some background on MIPS and Java bytecode, focusing on the function calling conventions.

MIPS has 32 registers which, like for most microprocessors, are fixed (I.e., it doesn't use SPARC-style register windows). In the MIPS ABI, four registers are used for passing arguments to functions. These arguments, and any additional arguments, are backed by the stack, as illustrated in the figure below.



So to call a function with five 32-bit arguments, the caller would put the first four in registers a0..a3 (the blue boxes in the figure) and the fifth on the stack (the pink box). If there are fewer arguments, they are all placed in registers. Function return values are also passed via registers, using the v0/v1 register pair. For 32-bit return values, only v0 is used, and if more than 64-bits are needed, the rest will be copied via the stack.

The ABI also specifies a set of callee-saved registers (s0..s7) and a stack pointer (sp). The other registers are basically used for temporaries and are allowed to be overwritten by the callee. (I'm ignoring some special cases here, which can be handled with compiler options).


How does this translate into Java bytecode then? I've explained how Cibyl works in more details in other articles, but a recap can be good. The important part here is how MIPS registers are handled. A naïve implementation would use static integer class members in Java to represent registers, which would correspond nicely with how actual MIPS registers are implemented. All C functions can then be translated into Java prototypes void fn_name(void), since all register values are always available statically. In fact, this is how the very first Cibyl release was implemented. I say it's naïve because it's quite inefficient as well. It tends to generate code such as
	iconst_1
        putstatic CRunTime/t0 I
	iconst_2
        putstatic CRunTime/t1 I
	...
	getstatic CRunTime/t0 I
	getstatic CRunTime/t1 I
	iadd
	putstatic CRunTime/t2 I

and getstatics and putstatics are both slow and big (bytecode-wise).

So instead, Cibyl uses Java local variables to represent MIPS registers. This allows for much more efficient and compact bytecode to be generated, but instead gives us a problem with functions: You now need to pass all registers which pass values between caller and callee to the callee function. Luckily, this actually boils down to only the argument registers, and the stack pointer. All the other registers are either local temporaries, which we can just throw away, or callee-saved registers, which are saved automatically since function-locals are used.


Let's look at how a function call in Java bytecode works. Java bytecode is a stack-oriented architecture, i.e., all operations are done on values on an operand stack. For example, an integer addition is done by pushing two values on the operand stack, and executing an iadd instruction which will pop them and push back the result. The figure below shows how a function is called:



i.e., the caller will push some values on the operand stack and then invoke the method. Since Java is typesafe, the correct number of arguments must be on the operand stack, or the JVM will not load the program. On the call, the callee will receive the arguments not on the operand stack, but placed in local variables (the first n), which is where they would typically end up anyway. To return a value, it's again pushed on the operand stack and returned via the ireturn instruction (for integer return values). When control returns to the caller, it can find the value at the top of the stack. In the figure, the blue boxes represent the arguments and the code shows an example function call.

Fine. So most of you can now guess how Cibyl handles MIPS argument registers: a0...a3 is simply pushed on the operand stack and ends up as local variables in the function. In addition, the stack pointer sp is also pushed, as it's value is needed by both caller and callee. Other registers are simply allocated and used locally.


But how does Cibyl know which of the argument registers to pass? Now we're getting to the point! Trivially it could pass all argument registers to all functions, but that's unnecessary since not all functions have that many parameters. More function arguments also mean higher overhead, and we'd like to avoid that. So far, Cibyl has simply checked if the argument registers and the stack pointer are used by the function, and then pass the needed ones. Unfortunately, a0..a3 can sometimes be used as local temporaries as well - even though they are not function parameters. In this case, Cibyl would pass them in vain, inducing extra overhead for no gain. Luckily, through DWARF there is a better way.

The idea comes from Marcus Groeber, who noticed this while playing with Cibyl. The DWARF debugging information actually contains all information we need to find out which arguments registers are actually used as parameters. The last post describes how to look this up. So what's left to do in Cibyl is simply to note this down, and only pass the actual parameters. The same goes for the return values.

In effect, the prototypes in the generated Java methods now become basically the same as the original C functions. Some cases are still tricky, namely parameters and return values that are larger than 32 bits. For these, I simply revert back to the old behavior. These are fortunately pretty uncommon, in C and C++, mostly either small values or pointers are passed around.


I've not yet done any real performance measurements with the new approach, and indeed, I've managed to introduce a regression which I haven't yet tracked down. But around 3% of the instructions in a large program (Frodo, the C64 emulator) are pruned with this approach. I would guess that the reduced overhead should be measurable for most applications, although probably not dramatic.

So in conclusion: DWARF debugging information makes for an interesting way of optimizing function calls for Cibyl. It also brings the Java bytecode translation a bit close to the original C program, which should be nice for those that like to read Java bytecode assembly!


Update: The regression has been found and fixed. I've also moved the entire Cibyl source to github. Git is simply better than svn...

DWARF: function return value types and parameter types

I've recently had to look deeper into the DWARF debugging standard. DWARF is the debugging format used in the ELF executable format, commonly used by debuggers, but also in tools like my Kcov code coverage tool. It's complex and quite a bit daunting to get the grips on. Anyway, I have a small project where I needed help from DWARF. What I wanted from DWARF is the following:
  • Looking up the type of function return values

  • Looking up the type and number of arguments to functions
And in this post, I'll explain how to do just this in code and illustrations. First some prerequisites though. You don't need to parse the ELF file manually (fortunately), but can rely on libraries to do this. Unfortunately, there are two DWARF libraries - which are not compatible with one antoher.

The two libraries are libdwarf and libdw/elfutils. libdwarf is the original one, while elfutils is a newer library which promises a slightly simplified and more modern API. They both install /usr/include/dwarf.h though, so you can only have one of the development libraries installed. elfutils is easier to find examples for, so I wanted to use that. Unfortunately, Kcov is written for libdwarf (by Thomas Neumann), so I first rewrote that to use libdw instead.


So on to some DWARF concepts and an overview of my problem. A deeper introduction can be found in the Introduction to the DWARF debugging format by Michael J. Eager, written for the standard committee. Here, I'll limit myself to the steps needed to solve my particular issue. The figure below illustrates the data structures used for function return values and parameters.



The basic structure in DWARF is the DIE, the Debugging Information Entry. Each of the big, rounded blobs in the figure are DIEs. These are structued in a tree of sorts, where a DIE can have children and siblings. Each DIE is identified by a tag, which describes what type of DIE we're dealing with. The colors of the rounded blobs signify the tags, or DIE types. A DIE can also have attributes, which describe, well, attributes of the DIE. For example, DIEs often have names (a function name), types (a reference to int, double, etc) and sizes (the size of a type).

Now, if we want to get the function return type and parameter types, it should be clear that we need to traverse the DIE tree to lookup functions and their children. From there, we can get the types through the DIE attributes. I'll describe in code how to do this with libdw from elfutils. The full code is listed here, and the code below is simplified, skipping error checks and some application-specific setuff. So let's begin.
  /* Initialize libdwarf */
  dbg = dwarf_begin_elf(this->elf, DWARF_C_READ, NULL);

... with initializing libdwarf from an ELF-structure. This returns a pointer to a DWARF context. We continue by iterating through the compilation units, which is done in two steps:
  while (dwarf_nextcu(dbg, offset, &offset, &hdr_size, 0, 0, 0) == 0) {
      Dwarf_Die result, cu_die;

      if (dwarf_offdie(dbg, last_offset + hdr_size, &cu_die) == NULL)
        break;
      last_offset = offset;

the first of which looks up the offset into the ELF of the compilation unit, and the second returns the DIE for this. As you can see in the figure, we're actually intersted in the child of the compilation unit - where the functions are.
      if (dwarf_child (&cu_die, &result) != 0)
        continue;

So dwarf_child just places the child DIE in the result variable. We then want to iterate through the childs siblings and do something for each function:
      do {
          switch (dwarf_tag(&result))
          {
          case DW_TAG_subprogram:
          case DW_TAG_entry_point:
          case DW_TAG_inlined_subroutine:
            this->handleDwarfFunction(&result);
            break;
          default:
            break;
          }
      } while(dwarf_siblingof(&result, &result) == 0);

And here we check the tag of the DIE and call a helper routine for each function. So onto handleDwarfFunction():

void CibylElf::handleDwarfFunction(Dwarf_Die *fun_die)
{
  attr = dwarf_attr_integrate(fun_die, DW_AT_type, &attr_mem);
  ret_size = mips_arg_size(elf, fun_die, attr);

We first lookup the DW_AT_type attribute of the function, which is the return type of the function. mips_arg_size() is a helper function which return the size of this attribute (if it can be derived). It's taken from elfutils and will iterate through typedefs etc to get to the actual type. We'll skip that here though. In the figure, the return value attribute is represented by the square box in the lower left. For the parameters, we'll need to recurse down to the children of the function:

  if (dwarf_child (fun_die, &result) != 0)
    return;

  do {
      switch (dwarf_tag (&result))
      {
      case DW_TAG_formal_parameter:
        attr = dwarf_attr_integrate(&result, DW_AT_type, &attr_mem);
        arg_size = mips_arg_size(elf, fun_die, attr);
        break;
      case DW_TAG_inlined_subroutine:
        /* Recurse further down */
        this->handleDwarfFunction(&result);
        break;
      default:
        break;
      }
  } while(dwarf_siblingof(&result, &result) == 0);
}

so, similar to what we had before, we lookup the child and then each sibling of the child. From the tag of it we can see if it is actually a parameter, and then convert the type attribute to the size by the mips_arg_size() helper.


So that's it. Not so difficult, right? Well, not when you know how to do it - but I can assure you that this took quite a bit of time to find out.

And what's the use of it then? That's for the next post!