Question

When i adding map files in 64 bit Delphi XE4 project (debug mode). Iv got some symbols like "_zn6", "_zn11" and etc. What the reason of it? In 32 bit project everything is good. If i chooses release mode then information is clear but very poor. Fragment of map file:

 0005:0000B970       System.Rtti.$pdata$_ZN6System8Generics11Collections8TList__1IPNS_7Typinfo9TTypeInfoEE6RemoveES5_
 0005:0000B97C       System.Rtti.$pdata$_ZN6System8Generics11Collections8TList__1IPNS_7Typinfo9TTypeInfoEE10RemoveItemES5_NS_5Types10TDirectionE
 0005:0000B988       System.Rtti.$pdata$_ZN6System8Generics11Collections8TList__1IPNS_7Typinfo9TTypeInfoEE6DeleteEi
 0005:0000B994       System.Rtti.$pdata$_ZN6System8Generics11Collections8TList__1IPNS_7Typinfo9TTypeInfoEE11DeleteRangeEii
 0005:0000B9AC       System.Rtti.$pdata$_ZN6System8Generics11Collections8TList__1IPNS_7Typinfo9TTypeInfoEE7ExtractES5_
 0005:0000B9B8       System.Rtti.$pdata$_ZN6System8Generics11Collections8TList__1IPNS_7Typinfo9TTypeInfoEE11ExtractItemES5_NS_5Types10TDirectionE
 0005:0000B9C4       System.Rtti.$pdata$_ZN6System8Generics11Collections8TList__1IPNS_7Typinfo9TTypeInfoEE8ExchangeEii
 0005:0000B9D0       System.Rtti.$pdata$_ZN6System8Generics11Collections8TList__1IPNS_7Typinfo9TTypeInfoEE4MoveEii
 0005:0000B9DC       System.Rtti.$pdata$_ZN6System8Generics11Collections8TList__1IPNS_7Typinfo9TTypeInfoEE5FirstEv
 0005:0000B9E8       System.Rtti.$pdata$_ZN6System8Generics11Collections8TList__1IPNS_7Typinfo9TTypeInfoEE4LastEv
 0005:0000B9F4       System.Rtti.$pdata$_ZN6System8Generics11Collections8TList__1IPNS_7Typinfo9TTypeInfoEE5ClearEv
 0005:0000BA00       System.Rtti.$pdata$_ZN6System8Generics11Collections8TList__1IPNS_7Typinfo9TTypeInfoEE6ExpandEv
 0005:0000BA0C       System.Rtti.$pdata$_ZN6System8Generics11Collections8TList__1IPNS_7Typinfo9TTypeInfoEE8ContainsES5_
 0005:0000BA18       System.Rtti.$pdata$_ZN6System8Generics11Collections8TList__1IPNS_7Typinfo9TTypeInfoEE7IndexOfES5_
 0005:0000BA24       System.Rtti.$pdata$_ZN6System8Generics11Collections8TList__1IPNS_7Typinfo9TTypeInfoEE11IndexOfItemES5_NS_5Types10TDirectionE
 0005:0000BA30       System.Rtti.$pdata$_ZN6System8Generics11Collections8TList__1IPNS_7Typinfo9TTypeInfoEE11LastIndexOfES5_
 0005:0000BA3C       System.Rtti.$pdata$_ZN6System8Generics11Collections8TList__1IPNS_7Typinfo9TTypeInfoEE7ReverseEv
 0005:0000BA48       System.Rtti.$pdata$_ZN6System8Generics11Collections8TList__1IPNS_7Typinfo9TTypeInfoEE4SortEv
 0005:0000BA54       System.Rtti.$pdata$_ZN6System8Generics11Collections8TList__1IPNS_7Typinfo9TTypeInfoEE4SortENS_15DelphiInterfaceINS0_8Defaults12IComparer__1IS5_EEEE
 0005:0000BA60       System.Rtti.$pdata$_ZN6System8Generics11Collections8TList__1IPNS_7Typinfo9TTypeInfoEE12BinarySearchES5_Ri
 0005:0000BA6C       System.Rtti.$pdata$_ZN6System8Generics11Collections8TList__1IPNS_7Typinfo9TTypeInfoEE12BinarySearchES5_RiNS_15DelphiInterfaceINS0_8Defaults12IComparer__1IS5_EEEE
 0005:0000BA78       System.Rtti.$pdata$_ZN6System8Generics11Collections8TList__1IPNS_7Typinfo9TTypeInfoEE10TrimExcessEv
 0005:0000BA84       System.Rtti.$pdata$_ZN6System8Generics11Collections8TList__1IPNS_7Typinfo9TTypeInfoEE7ToArrayEv
 0005:0000BA90       System.Rtti.$pdata$_ZN6System8Generics11Collections8TList__1IPNS_7Typinfo9TTypeInfoEE13GetEnumeratorEv
 0005:0000BA9C       System.Rtti.$pdata$_ZN6System8Generics11Collections8TList__1IPNS_7Typinfo9TTypeInfoEE11TEnumeratorIE10GetCurrentEv
 0005:0000BAA8       System.Rtti.$pdata$_ZN6System8Generics11Collections8TList__1IPNS_7Typinfo9TTypeInfoEE11TEnumeratorIE12DoGetCurrentEv
 0005:0000BAB4       System.Rtti.$pdata$_ZN6System8Generics11Collections8TList__1IPNS_7Typinfo9TTypeInfoEE11TEnumeratorIE10DoMoveNextEv
 0005:0000BAC0       System.Rtti.$pdata$_ZN6System8Generics11Collections8TList__1IPNS_7Typinfo9TTypeInfoEE11TEnumeratorIEC3EPNS2_IS5_EE
 0005:0000BAD8       System.Rtti.$pdata$_ZN6System8Generics11Collections8TList__1IPNS_7Typinfo9TTypeInfoEE11TEnumeratorIE8MoveNextEv

Here is JCL log sample (with x64 map files):

ERR (ThreadID=12E0 25.01.2014 23:06:28:098) - External exception E06D7363
Exception class: EExternalException
Exception address: 000007FEFD7DBCCD
Stack list, generated 25.01.2014 23:06:27
[000007FEFD7DBCCD] RaiseException + $3D
[00000000775797A8] RtlRaiseException + $248
[000007FEFD7DBCCD] RaiseException + $3D
[000007FEEC70E92C] _CxxThrowException + $D4
[000007FEECB88383] Unknown function at ?GetTotal@ColumnDesc@TablesManager@ProviderEngine@@QEBA_KXZ + $1BF3
[000007FEECB7EB49] Unknown function at DllCanUnloadNow + $33F69
[000007FEECB7B160] Unknown function at DllCanUnloadNow + $30580
[000007FEECB7CC9D] Unknown function at DllCanUnloadNow + $320BD
[00000000030F115D] ConnPool.GetSKRowset (Line 1220, "ConnPool.pas" + 25) + $27
[00000000030F20B2] ConnPool._ZN8Connpool11TConnection9GetResultEN6System15DelphiInterfaceIN6Winapi6Adoint10_RecordsetEEEN11Definitions9TDCReturnENS1_3SetINS_16TRecordsetOptionELSA_0ELSA_2EEEPNS1_7TObjectEb (Line 1341, "ConnPool.pas" + 27) + $1B
[00000000030EEFFF] ConnPool._ZN8Connpool11TConnection18InternalExecuteCmdEv (Line 974, "ConnPool.pas" + 134) + $0
[00000000030EE56E] ConnPool._ZN8Connpool11TConnection7ExecuteEPNS_12TCmdExecArgsE (Line 801, "ConnPool.pas" + 8) + $0
[00000000031C1B97] SKDS._ZN4Skds13TConfigReader7ExecCmdEiN6System13UnicodeStringES2_RKNS1_10OleVariantEPN8Connpool15TCmdExecOptionsEiNS6_9TTranModeEPS3_SA_i (Line 439, "SKDS.pas" + 65) + $0
[00000000031AD053] Dataservice.DoSimpleCall (Line 3241, "Dataservice.pas" + 8) + $167
[00000000031AD929] Dataservice._ZN11Dataservice12TDataservice10RunCommandEiN6System10WideStringES2_RKNS1_10OleVariantES5_RS3_ (Line 3336, "Dataservice.pas" + 44) + $0
[000007FEFE2216D0] Unknown function at SetErrorInfo + $80
[000007FEFE2224D2] DispCallFunc + $262
[000007FEFE221DE1] Unknown function at SetErrorInfo + $791
[0000000002F18242] System.Win.ComObj._ZN6System3Win6Comobj11TAutoObject6InvokeEiRK5_GUIDitPvS6_S6_S6_ + $82
[000000000073407F] Invoker._ZN7Invoker9TKInvoker6InvokeEv (Line 177, "Invoker.pas" + 30) + $73
[00000000007613A5] WorkerThread._ZN12Workerthread14TKWorkerThread17IntCallFromMemoryEN6System15DelphiInterfaceI7IStreamEEii (Line 426, "WorkerThread.pas" + 16) + $0
[0000000000760728] WorkerThread._ZN12Workerthread14TKWorkerThread10WorkInvokeEN6System15DelphiInterfaceI7IStreamEES4_ (Line 391, "WorkerThread.pas" + 59) + $0
[000000000075EEC1] WorkerThread.ProcessRequest (Line 195, "WorkerThread.pas" + 37) + $50
[000000000075F36E] WorkerThread._ZN12Workerthread14TKWorkerThread11DoSomethingEv (Line 218, "WorkerThread.pas" + 4) + $8
[0000000000737038] PoolableThread._ZN14Poolablethread16TKPoolableThread7ExecuteEv (Line 259, "PoolableThread.pas" + 17) + $E
[000000000052C89B] System.Classes._ZN6System7Classes10ThreadProcEPNS0_7TThreadE + $3B
[000000000040DACB] System._ZN6System13ThreadWrapperEPv + $3B
[000000007735652D] BaseThreadInitThunk + $D
[000000007758C521] RtlUserThreadStart + $21
Était-ce utile?

La solution

These extra names are related to the different exception handling model on x64. On x86 exceptions are stack based. On x64 they are table based. This has consequences for how the compiler treats except and finally blocks.

In particular, the compiler/linker has to be able output an exception table that describes the exception handling code. As I understand it, the names that you see with $pdata$ and $unwind$ are created by the compiler when it processes except and finally blocks. These names are then used by the linker to create the exception table that is written to the executable output file. And the compiler generates such unspeakable names so that they don't clash with the true function names.

My guess is that you are seeing these names in your stack traces because the JCL stack walker code is not clever enough to decipher these names. If you were using madExcept, for instance, you would see the names that you were expecting.

So fundamentally, the problem is that JCL is lacking functionality.


There really is a huge difference between x86 and x64 structured exception handling. For instance, it is an interesting fact to note that the compiled code for a finally block appears twice in an x64 executable. Consider this short program:

procedure Foo;
begin
end;

procedure Main;
begin
  try
  finally
    Foo;
  end;
end;

begin
  Main;
end.

The compiler transforms Main into:

Project1.dpr.8: begin
0000000000409A30 55               push rbp
0000000000409A31 4883EC30         sub rsp,$30
0000000000409A35 488BEC           mov rbp,rsp
0000000000409A38 48896D28         mov [rbp+$28],rbp
Project1.dpr.9: try
0000000000409A3C 90               nop
Project1.dpr.11: Foo;
0000000000409A3D 90               nop
0000000000409A3E E8DDFFFFFF       call Foo
Project1.dpr.13: end;
0000000000409A43 488D6530         lea rsp,[rbp+$30]
0000000000409A47 5D               pop rbp
0000000000409A48 C3               ret
0000000000409A49 488D8000000000   lea rax,[rax+$00000000]
Project1.dpr.11: Foo;
0000000000409A50 55               push rbp
0000000000409A51 4883EC20         sub rsp,$20
0000000000409A55 488BEC           mov rbp,rsp
0000000000409A58 E8C3FFFFFF       call Foo
0000000000409A5D 488D6520         lea rsp,[rbp+$20]
0000000000409A61 5D               pop rbp
0000000000409A62 C3               ret

Note the two calls to Foo. The first one is normal execution. That is when there are no exceptions, and the finally block is entered normally. The second call to Foo deals with the case where an exception is active.

This second version of the finally block is actually compiled as a separate function. It has the name Project1.$pdata$_ZN8Project13FooEv according to my map file.

0005:00000A50       Project1.$pdata$_ZN8Project13FooEv

It is called from the main exception handler, System._DelphiExceptionHandler. And it really is a separate function as can be see by the fact that it ends with ret. If I throw an exception inside the try/finally to get this variant of code to run, the stack trace in the IDE looks like this:

Project1.Main
System._DelphiExceptionHandler($12FAB0,1244912,$12E820,$12E730)
:00000000779F9DAD ; ntdll.dll
:00000000779E8A4C ; ntdll.dll
:00000000778E2D3E ; C:\Windows\system32\kernel32.dll
System._DelphiExceptionHandler($12FAB0,1244976,$12F5C0,$12EF70)
:00000000779F9D2D ; ntdll.dll
:00000000779E91CF ; ntdll.dll
:0000000077A21248 ; ntdll.dll
:000007FEFDA7940D ; C:\Windows\system32\KERNELBASE.dll
System._RaiseAtExcept(???,???)
System._RaiseExcept(???)
Project1.Main

So as you can see, the IDE is able to achieve what the JCL code cannot, and make sense of the table based exception handling.

Under x86 is looks quite different:

Project1.Main
Project1.Project1
:7618336a kernel32.BaseThreadInitThunk + 0x12
:77be9f72 ntdll.RtlInitializeExceptionChain + 0x63
:77be9f45 ntdll.RtlInitializeExceptionChain + 0x36

So, these unspeakable names are all related to the management of table based exceptions. The behaviour is entirely to be expected.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top