This is an archive of the discontinued LLVM Phabricator instance.

[libunwind] Don't define unw_fpreg_t to uint64_t for __ARM_DWARF_EH__
ClosedPublic

Authored by mstorsjo on Jan 21 2019, 12:48 AM.

Details

Summary

The existing typedef of unw_fpreg_t to uint64_t might work and be correct for the ARM_EHABI case, but for dwarf, some cases in e.g. DwarfInstructions.hpp convert between double and unw_fpreg_t.

When converting implicitly between double and unw_fpreg_t (uint64_t), the values get interpreted as integers and converted to float and vice versa, while the correct thing would be to keep the same bit pattern.

Avoid the whole issue by using the same definition of unw_fpreg_t as all other architectures, when using dwarf unwinding on ARM.

AFAIK NetBSD uses dwarf unwinding on ARM, and I'm doing the same for MinGW/ARM.

I'm not aware of a testcase where the current setup of unw_fpreg_t would produce incorrect results, but building produces the following warnings:

src/libunwind.cpp:236:61: warning: format specifies type
      'double' but the argument has type 'unw_fpreg_t'
      (aka 'unsigned long long') [-Wformat]
                       static_cast<void *>(cursor), regNum, value);
                                                            ^~~~~

src/DwarfInstructions.hpp:178:20: warning: implicit conversion
      turns floating-point number into integer: 'double' to 'unw_fpreg_t' (aka 
      'unsigned long long') [-Wfloat-conversion]
                i, getSavedFloatRegister(addressSpace, registers, cfa,
                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Diff Detail

Event Timeline

mstorsjo created this revision.Jan 21 2019, 12:48 AM

I have no problem with the code change, but no context on whether or not it is correct.
I'm hoping some other people familiar with ARM and DWARF can chime in.

compnerd accepted this revision.Jan 24 2019, 9:24 AM

double should be safe for ARM DWARF EH, though, technically, long double is more appropriate of a type definition (the FPU state that is saved should be the widest floating point type). That would be long double (aka FP80 on x86, FP128 on AArch64/PPC, FP64 elsewhere). This happens to work because ARM uses FP64 irrespective of DWARF or EHABI.

This revision is now accepted and ready to land.Jan 24 2019, 9:24 AM
mstorsjo updated this revision to Diff 183776.Jan 27 2019, 2:27 PM

I had to update the signature of assembly functions which have got the concrete type of unw_fpreg_t in the mangled name. I chose to use void* for these functions, as I believe the same functions also are used for ARM EHABI, to avoid the need for different mangled versions of the assembly functions depending on exception handling mechanism.

I crafted a testcase which uses dwarf exceptions on arm, and this patch fixed restoring float registers in a case which previously was broken. So that confirms what the compiler warning tried to say.

This revision was automatically updated to reflect the committed changes.