LLVM Bugzilla is read-only and represents the historical archive of all LLVM issues filled before November 26, 2021. Use github to submit LLVM bugs

Bug 24233 - JITs should register unwind information (xdata) on Win64 to make longjmp and exceptions work
Summary: JITs should register unwind information (xdata) on Win64 to make longjmp and ...
Status: NEW
Alias: None
Product: libraries
Classification: Unclassified
Component: MCJIT (show other bugs)
Version: trunk
Hardware: PC Windows NT
: P normal
Assignee: Unassigned LLVM Bugs
URL:
Keywords:
: 12550 (view as bug list)
Depends on:
Blocks:
 
Reported: 2015-07-23 12:23 PDT by Reid Kleckner
Modified: 2016-09-14 04:54 PDT (History)
14 users (show)

See Also:
Fixed By Commit(s):


Attachments
Fib. example throwing exception (4.89 KB, text/plain)
2016-02-04 08:01 PST, gekkekoe
Details
ADDR32NB relocations (1.65 KB, patch)
2016-02-22 09:05 PST, Alexey Zasenko
Details
Modified Fib. example (7.17 KB, text/x-c++src)
2016-02-22 09:29 PST, Alexey Zasenko
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Reid Kleckner 2015-07-23 12:23:10 PDT
Currently RTDyldMemoryManager::registerEHFrames() implements this on Mac and Linux, but we need the same support for Win64. It involves calling RtlInstallFunctionTableCallback or RtlAddFunctionTable, as described on MSDN at https://msdn.microsoft.com/en-us/library/ft9x1kdx.aspx?f=255&MSPPError=-2147217396.
Comment 1 Lang Hames 2015-07-23 12:41:54 PDT
Hi Reid,

I want to avoid adding this to RTDyldMemoryManager::registerEHFrames if possible. I'm actually going to propose on llvm-dev that we take the existing registration code out of the base class and require clients to call it manually. The problem is that since MCJIT is cross-process/cross-platform, clients can get caught unawares when the target EH frames are registered by default in the JIT process. When JITing cross target this can result in flat-out invalid frames getting registered (e.g. 32-bit target frames registered on a 64-bit host), with unpredictable results. There's also currently a memory leak in this code, as the frames aren't deregistered by default (at least on Darwin).

If there's any non-trivial helper code that we cold provide to wrap these functions I'd be happy for that to go in tree though. It'd be nice if all the client had to do was something along the lines of:

class MyMemMgr : public RuntimeDyld::MemoryManager {
public:
  void registerEHFrames() override { RegisterWin64EHFrames(...); }
  void deregisterEHFrames() override { DeregisterWin64EHFrames(...); }
  /// ... Other overrides ...
}
Comment 2 Reid Kleckner 2015-07-23 12:52:52 PDT
Sure, sounds reasonable. I'm not planning to work on this right now, I mostly wanted to get this filed to make it easier to explain why longjmp doesn't work with MCJIT on Win64.

I don't recall what the current status of MCJIT producing COFF files is, but I think that's the first step towards generating the right frame information in the first place.
Comment 3 Gideon Smeding 2015-10-19 09:56:57 PDT
We currently have the situation that, in windows, the callstack is lost inside jitted code even though we don't use exceptions or longjumps at that point.
That is, when stepping through the assembly instructions the callstack disappears when entering the call to a jitted function.

Similarly when a crash occurs in a jitted function (due to e.g. null pointer dereference) the debugger cannot show the callstack.

Is this also due to the same problem? If so, I'd be very interested in some helper code and/or a working example.
Comment 4 Reid Kleckner 2015-10-19 11:40:45 PDT
(In reply to comment #3)
> Is this also due to the same problem? If so, I'd be very interested in some
> helper code and/or a working example.

Yes, registering the UNWIND_INFO tables should solve the problems you described.

Unfortunately, I don't know of any small example apps that use this API that I can point at. There are large examples like CoreCLR.
Comment 5 Reid Kleckner 2015-10-21 15:28:09 PDT
*** Bug 12550 has been marked as a duplicate of this bug. ***
Comment 6 gekkekoe 2016-02-04 08:01:04 PST
Created attachment 15826 [details]
Fib. example throwing exception
Comment 7 gekkekoe 2016-02-04 08:05:13 PST
Hi all,

I did some testing with this issue under Win64 and the exception handling works sometimes.

I modified the example from duplicate bug report 12550 to work with 3.7.1 and MCJit. I'm recursively traversing in a generated function, eventually the generated function calls an static function that throws a std::runtime_error.

If I don't invoke the FibF->dump() at line 152, the exception handling works as expected. But if I do enable that call, the the exception is not handled.

So why is the dump() call having affect on the EH data ?
The win64 EH seems to work magically except when certain function have been called. I'm trying to find a workaround for EH in win64. I'd rather not MCJIT if possible :)
Comment 8 Alexey Zasenko 2016-02-22 09:05:48 PST
Created attachment 15930 [details]
ADDR32NB relocations

Hi all,

In my project I've solved this issue passing Function Table from .pdata to RtlAddFunctionTable. But resolving of IMAGE_REL_AMD64_ADDR32NB relocations  is incomplete in LLVM. All relocations are filling with zeros now. So I added trivial RVA calculation here and then saved ".pdata" section instead of ".xdata" for passing to MemoryManager::registerEHFrames. Here I attached patch file.

Potential problem is as described in comments:
 // Note ADDR32NB requires a well-established notion of
 // image base. This address must be less than or equal
 // to every section's load address, and all sections must be
 // within a 32 bit offset from the base.

Proposed code doesn't manage sections load addresses.
Comment 9 Alexey Zasenko 2016-02-22 09:29:26 PST
Created attachment 15931 [details]
Modified Fib. example

I've modified previous sample to show how I registered the function table.
Custom memory manager is required to catch image base and implement final registerEHFrames function.

This sample is rough enough and may contain errors.

P.S. Can anyone propose more accurate way to retrieve Image Base pointer?
What is the difference between LoadAddr and Addr of section?
Comment 10 Andy Ayers 2016-02-22 10:41:07 PST
There are some built-in assumptions in RUNTIME_FUNCTION. PE files are guaranteed to occupy no more than a 4GB extent when loaded, so 32 bit offsets plus the base of the loaded image are enough to identify locations within the image.

Hence the RUNTIME_FUNCTION structure expects that the unwind data (.pdata and .xdata) will be located sufficiently "close" to the function that 32 bit offsets are sufficient. You need to provide these same guarantees, somehow.

The actual loaded location of the .pdata doesn't matter since you will report this information yourself via RtlAddFunctionTable. But the location of the .xdata does matter, and that's the tricky bit.

So here's a sketch of a solution.

RTDyld will relocate each .text section independently. Call RtlAddFunctionTable once per .text section, setting the BaseAddress to the address of the relocated base of the section. Then use the contents of the associated .pdata as the function table. You can safely ignore the relocations on the begin/end members, since the underlying values are already correct if the base of the image is the same as the base of the section.

Then, you must, somehow, guarantee that the associated .xdata is loaded at a higer address than the .text, within 4GB. Compute the 32 bit delta from the start of the relocated .text and this relocated .xdata, and add that delta to the UnwindInfoAddress fields for each RUNTIME_FUNCTION in the .pdata section.
Comment 11 Alexey Zasenko 2016-02-22 11:51:14 PST
(In reply to comment #10)
> There are some built-in assumptions in RUNTIME_FUNCTION. 

Yes, I know about these limitations. Some special MemoryManager should be implemented to guarantee 32 bit delta between sections. 

> RTDyld will relocate each .text section independently. Call
> RtlAddFunctionTable once per .text section, setting the BaseAddress to the
> address of the relocated base of the section. Then use the contents of the
> associated .pdata as the function table. You can safely ignore the
> relocations on the begin/end members, since the underlying values are
> already correct if the base of the image is the same as the base of the
> section.
> 
> Then, you must, somehow, guarantee that the associated .xdata is loaded at a
> higer address than the .text, within 4GB. Compute the 32 bit delta from the
> start of the relocated .text and this relocated .xdata, and add that delta
> to the UnwindInfoAddress fields for each RUNTIME_FUNCTION in the .pdata
> section.

Thanks for valuable reply. As I understand if the 32 bit difference is guaranteed all relocations will be safely performed by RTDyld.
Comment 12 Stefan Gränitz 2016-09-14 04:54:31 PDT
> Thanks for valuable reply. As I understand if the 32 bit difference is 
> guaranteed all relocations will be safely performed by RTDyld.

Don't want to add more noise to this issue. Just in case anyone wants to workaround the 64-bit relocations issue on Win64, you may want to use this patch to RuntimeDyldCOFFX86_64.h
https://github.com/weliveindetail/pj-llvm/commit/f9f26dc8bf511dde02142dc2cf361f67b4964985

Works great for us, I just didn't find the time to push this upstream.