Hi, While building packages for openSUSE-ARM, we realized that every time a program wanted to throw an exception, hell broke lose. After a lot of debugging and valgrind'ing, we found out that the ARM unwind tables contain garbage because they get written out without being initialized to 0. A simple failing test program: #include <stdio.h> int main(int argc, char **argv) { try { throw -1; } catch (int) { fprintf(stderr, "We caught an exception of type int\n"); } return 0; } Working test output: We caught an exception of type int Working unwind tables: 0x8640 <main>: @0x8734 Personality routine: 0x85bc <__gxx_personality_v0@@CXXABI_1.3> 0x97 vsp = r7 0x03 vsp = vsp + 16 0x84 0x08 pop {r7, r14} 0xb0 finish 0xb0 finish 0xb0 finish Failing test output: terminate called after throwing an instance of 'int' terminate called recursively Aborted (core dumped) Failing unwind tables: 0x8634 <main>: 0xffffffd0 Compact model 127 [reserved] valgrind output of gas: ==2009== Syscall param write(buf) points to uninitialised byte(s) ==2009== at 0x48EE56C: write (in /lib/libc-2.14.1.so) ==2009== by 0x48B51BB: _IO_file_write@@GLIBC_2.4 (fileops.c:1281) ==2009== by 0x48B510F: new_do_write (fileops.c:535) ==2009== by 0x48B5E1D: _IO_do_write@@GLIBC_2.4 (fileops.c:508) ==2009== by 0x48B6907: _IO_switch_to_get_mode (genops.c:189) ==2009== by 0x48B52D3: _IO_file_seekoff@@GLIBC_2.4 (fileops.c:991) ==2009== by 0x48AF0AB: _IO_seekoff_unlocked (ioseekoff.c:71) ==2009== by 0x48B4031: fseeko64 (fseeko64.c:42) ==2009== by 0x73A79: bfd_seek (bfdio.c:315) ==2009== by 0x5CB6F: _bfd_elf_write_object_contents (elf.c:5217) ==2009== by 0x4099F: bfd_close (opncls.c:701) ==2009== by 0x16E51: output_file_close (output-file.c:65) ==2009== Address 0x4d500d7 is not stack'd, malloc'd or (recently) free'd ==2009== Uninitialised value was created by a heap allocation ==2009== at 0x482F694: malloc (vg_replace_malloc.c:263) ==2009== by 0x7F353: xmalloc (xmalloc.c:147) ==2009== by 0x48BE1D7: _obstack_begin (obstack.c:186) ==2009== by 0x1C3E9: subseg_set_rest (subsegs.c:110) ==2009== by 0x1C50D: subseg_force_new (subsegs.c:195) ==2009== by 0x3B257: obj_elf_change_section (obj-elf.c:583) ==2009== by 0x25A47: start_unwind_section (tc-arm.c:19828) ==2009== by 0x3240D: create_unwind_entry (tc-arm.c:19857) ==2009== by 0x1B59D: read_a_source_file (read.c:919) ==2009== by 0xAEC1: main (as.c:1089) We also created a temporary patch to make it work by just initializing all memory properly: Index: libiberty/xmalloc.c =================================================================== --- libiberty/xmalloc.c.orig +++ libiberty/xmalloc.c @@ -60,6 +60,7 @@ function will be called to print an erro */ +#include <string.h> #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -145,6 +146,7 @@ xmalloc (size_t size) if (size == 0) size = 1; newmem = malloc (size); + memset(newmem, 0, size); if (!newmem) xmalloc_failed (size); With that patch applied, unwind tables are created successfully.
Hi Alexander, Would it be possible for you to upload a copy of the broken test executable ? I want to be able to look at the unwind information it contains, and to compare it against executables that I build locally. (I do not have an ARM system so I cannot run any executables. I just have a cross-hosted toolchain). Cheers Nick
Created attachment 6080 [details] source, broken and properly compiled binary Sure, please beware that the unwind table generation depends heavily on the contents of your host RAM though. I had one box where compilation worked just fine and one where it was constantly broken, which was how I ended up narrowing down the problem. So even if it works for your on your system it doesn't mean that it would always work.
Hi Alexander, Thanks for the binaries - they really help. If you compare a hex dump of the .ARM.exidx sections in the two binaries, you will see that the broken binary does not contain garbage, just two erroneous set bits: % readelf -x17 exc Hex dump of section '.ARM.exidx': 0x00008758 70feffff 01000000 e0feff7f d0ffff7f p............... 0x00008768 54ffffff ad08b180 90ffffff b0b0b080 T............... 0x00008778 8cffff7f 01000000 ........ % readelf -x17 exc.broken Hex dump of section '.ARM.exidx': 0x0000874c 70feffff 01000000 e0feffff d0ffffff p............... 0x0000875c 54ffffff ad08b180 90ffffff b0b0b080 T............... 0x0000876c 8cffff7f 01000000 ........ (It would be very interesting to compare the exc.o files for the broken and working builds to see if these bits are the same there. Ie I am wondering if the linker might be the problem rather than the assembler - and the valgrind detection of an uninitialised write might just be a red herring). I am still investigating, but in the meantime would you mind trying out the small patch that I am about to upload and let me know if it makes any difference ? Cheers Nick
Created attachment 6083 [details] possible bug fix
I can easily create the .o files for you. I'm very sure that gas is broken. Please see the following commands: panda1:/binutils/gas> ./as-new -march=armv7-a -mfloat-abi=hard -mfpu=vfpv3-d16 -meabi=5 -o /exc.o /exc.s panda1:/binutils/gas> readelf -u /exc.o Unwind table index '.ARM.exidx' at offset 0xf8 contains 1 entries: 0x0: 0xfffffffc Compact model 127 [reserved] ----- wichary:/binutils/gas> ./as-new -march=armv7-a -mfloat-abi=hard -mfpu=vfpv3-d16 -meabi=5 -o /exc.o /exc.s wichary:/binutils/gas> readelf -u /exc.o Unwind table index '.ARM.exidx' at offset 0xf8 contains 1 entries: 0x0: @0x0 Personality routine: 0x0 <main> ----- Both are running inside the exact same rootfs mounted via NFS. This is with your patch applied btw :).
Another data point I forgot to mention: Running gas inside of valgrind generates correct unwind tables even on panda1.
Created attachment 6084 [details] exc.s and working/broken .o files
Created attachment 6086 [details] Another possible fix
Hi Alexander, Thanks for the .s and .o files. I agree - the problem must be with GAS. Please could you try out the newly uploaded patch and let me know if it makes a difference ? I still cannot reproduce the bug locally, but at least I am able to improve readelf so that it produces more helpful output when decoding the unwind tables. Cheers Nick
Created attachment 6090 [details] Third possible fix
Hi Alexander, Thinking about this some more over the weekend, I now suspect that my second patch will not work. But I have thought of another possible cause, and uploaded a third patch. Please could you try out both patches and let me know if they make any difference. Cheers Nick
Hi Nick, Sorry for the late reply. I fetched today's CVS and realized that you already applied patch 3. I now get the following output when compiling on panda1: Unwind table index '.ARM.exidx' at offset 0xf8 contains 1 entries: 0x0: @0x0 Compact model 0 0x00 vsp = vsp + 4 0x00 vsp = vsp + 4 0x00 vsp = vsp + 4 The difference in the two outputs is obviously the compact model bit: --- exc.good.o.hex 2011-12-20 14:54:09.000000000 +0000 +++ exc.bad.o.hex 2011-12-20 14:54:13.000000000 +0000 @@ -11,7 +11,7 @@ 000000a0 fe ff 4f f0 00 03 18 46 07 f1 10 07 bd 46 80 bd |..O....F.....F..| 000000b0 57 65 20 63 61 75 67 68 74 20 61 6e 20 65 78 63 |We caught an exc| 000000c0 65 70 74 69 6f 6e 20 6f 66 20 74 79 70 65 20 69 |eption of type i| -000000d0 6e 74 0a 00 00 00 00 00 84 03 97 01 b0 b0 b0 08 |nt..............| +000000d0 6e 74 0a 00 00 00 00 80 84 03 97 01 b0 b0 b0 08 |nt..............| 000000e0 ff 00 15 01 0c 28 04 34 01 30 10 00 00 66 04 2c |.....(.4.0...f.,| 000000f0 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000100 00 47 43 43 3a 20 28 53 55 53 45 20 4c 69 6e 75 |.GCC: (SUSE Linu|
This patch fixes the test case for me: Index: config/tc-arm.c =================================================================== RCS file: /cvs/src/src/gas/config/tc-arm.c,v retrieving revision 1.512 diff -u -r1.512 tc-arm.c --- config/tc-arm.c 15 Dec 2011 10:21:49 -0000 1.512 +++ config/tc-arm.c 20 Dec 2011 15:03:02 -0000 @@ -19944,6 +19944,7 @@ /* Allocate the table entry. */ ptr = frag_more ((size << 2) + 4); + memset (ptr, 0, (size << 2) + 4); where = frag_now_fix () - ((size << 2) + 4); switch (unwind.personality_index)
CVSROOT: /cvs/src Module name: src Changes by: nickc@sourceware.org 2011-12-21 17:07:27 Modified files: gas : ChangeLog gas/config : tc-arm.c Log message: PR gas/13449 * config/tc-arm.c (create_unwind_entry): Zero allocated table entries. Patches: http://sourceware.org/cgi-bin/cvsweb.cgi/src/gas/ChangeLog.diff?cvsroot=src&r1=1.4638&r2=1.4639 http://sourceware.org/cgi-bin/cvsweb.cgi/src/gas/config/tc-arm.c.diff?cvsroot=src&r1=1.512&r2=1.513
Patch applied.