psabieh.inc 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Translated to Pascal by Jonas Maebe,
  4. member of the Free Pascal development team
  5. This file is based on the source code of libsupc++ from GCC 4.2.1.
  6. See below for details about the copyright. While it is GPLv2 rather
  7. than LGPLv2 like the rest of the FPC RTL, it has the same linking
  8. exception as the rest of the FPC RTL and hence it can be used in the
  9. same way.
  10. **********************************************************************}
  11. // -*- C++ -*- The GNU C++ exception personality routine.
  12. // Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
  13. //
  14. // This file is part of GCC.
  15. //
  16. // GCC is free software; you can redistribute it and/or modify
  17. // it under the terms of the GNU General Public License as published by
  18. // the Free Software Foundation; either version 2, or (at your option)
  19. // any later version.
  20. //
  21. // GCC is distributed in the hope that it will be useful,
  22. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  24. // GNU General Public License for more details.
  25. //
  26. // You should have received a copy of the GNU General Public License
  27. // along with GCC; see the file COPYING. If not, write to
  28. // the Free Software Foundation, 51 Franklin Street, Fifth Floor,
  29. // Boston, MA 02110-1301, USA.
  30. // As a special exception, you may use this file as part of a free software
  31. // library without restriction. Specifically, if other files instantiate
  32. // templates or use macros or inline functions from this file, or you compile
  33. // this file and link it with other files to produce an executable, this
  34. // file does not by itself cause the resulting executable to be covered by
  35. // the GNU General Public License. This exception does not however
  36. // invalidate any other reasons why the executable file might be covered by
  37. // the GNU General Public License.
  38. {$packrecords c}
  39. {$ifdef linux}
  40. {$linklib c}
  41. {$linklib libgcc_s}
  42. {$endif}
  43. {$ifdef __ARM_EABI_UNWINDER__}
  44. {$define PSABIEH_NO_SIZEOF_ENCODED_VALUE}
  45. {$endif}
  46. function FPC_psabieh_GetExceptionWrapper(exceptionObject: PFPC_Unwind_Exception): PExceptObject; inline;
  47. begin
  48. { go to end of the wrapped exception (it's the last field in PFPC_Unwind_Exception), then to the start }
  49. result:=PExceptObject(exceptionObject+1)-1;
  50. end;
  51. function _Unwind_Resume_or_Rethrow (context:PFPC_Unwind_Context): FPC_Unwind_Reason_Code;cdecl;external;
  52. procedure _Unwind_DeleteException(context:PFPC_Unwind_Context);cdecl;external;
  53. function _Unwind_GetRegionStart(context:PFPC_Unwind_Context):PtrUInt;cdecl;external;
  54. function _Unwind_GetLanguageSpecificData(context:PFPC_Unwind_Context):PtrUInt;cdecl;external;
  55. function _Unwind_GetDataRelBase(context:PFPC_Unwind_Context):PtrUInt;cdecl;external;
  56. function _Unwind_GetTextRelBase(context:PFPC_Unwind_Context):PtrUInt;cdecl;external;
  57. {$ifdef __ARM_EABI_UNWINDER__}
  58. procedure _Unwind_Complete(exceptionObject: PFPC_Unwind_Exception);cdecl;external;
  59. function __gnu_unwind_frame(exception:PFPC_Unwind_Exception;context:PFPC_Unwind_Context):FPC_Unwind_Reason_Code;cdecl;external;
  60. type
  61. FPC_Unwind_VRS_RegClass = UInt32;
  62. const
  63. FPC_UVRSC_CORE = FPC_Unwind_VRS_RegClass(0); // integer register
  64. FPC_UVRSC_VFP = FPC_Unwind_VRS_RegClass(1); // vfp
  65. FPC_UVRSC_FPA = FPC_Unwind_VRS_RegClass(2); // fpa
  66. FPC_UVRSC_WMMXD = FPC_Unwind_VRS_RegClass(3); // Intel WMMX data register
  67. FPC_UVRSC_WMMXC = FPC_Unwind_VRS_RegClass(4); // Intel WMMX control register
  68. type
  69. FPC_Unwind_VRS_DataRepresentation = UInt32;
  70. const
  71. FPC_UVRSD_UINT32 = FPC_Unwind_VRS_DataRepresentation(0);
  72. FPC_UVRSD_VFPX = FPC_Unwind_VRS_DataRepresentation(1);
  73. FPC_UVRSD_FPAX = FPC_Unwind_VRS_DataRepresentation(2);
  74. FPC_UVRSD_UINT64 = FPC_Unwind_VRS_DataRepresentation(3);
  75. FPC_UVRSD_FLOAT = FPC_Unwind_VRS_DataRepresentation(4);
  76. FPC_UVRSD_DOUBLE = FPC_Unwind_VRS_DataRepresentation(5);
  77. type
  78. FPC_Unwind_VRS_Result = UInt32;
  79. const
  80. FPC_UVRSR_OK = FPC_Unwind_VRS_Result(0);
  81. FPC_UVRSR_NOT_IMPLEMENTED = FPC_Unwind_VRS_Result(1);
  82. FPC_UVRSR_FAILED = FPC_Unwind_VRS_Result(2);
  83. Function _Unwind_VRS_Set(context: PFPC_Unwind_Context; regclass: FPC_Unwind_VRS_RegClass;
  84. regnr: PTRUint {uw}; repr: FPC_Unwind_VRS_DataRepresentation;
  85. value: pointer): FPC_Unwind_VRS_Result; cdecl; external;
  86. function _Unwind_VRS_Get(context: PFPC_Unwind_Context; regclass: FPC_Unwind_VRS_RegClass;
  87. regnr: PTRUint {uw}; repr: FPC_Unwind_VRS_DataRepresentation;
  88. value: pointer): FPC_Unwind_VRS_Result; cdecl; external;
  89. procedure _Unwind_SetGR(context:PFPC_Unwind_Context;index:cint; new_value:PtrUInt); inline;
  90. begin
  91. _Unwind_VRS_Set(context,FPC_UVRSC_CORE, index, FPC_UVRSD_UINT32, @new_Value);
  92. end;
  93. function _Unwind_GetGR(context:PFPC_Unwind_Context;index:cint):PtrUInt; inline;
  94. begin
  95. _Unwind_VRS_Get(context,FPC_UVRSC_CORE, index, FPC_UVRSD_UINT32, @result);
  96. end;
  97. procedure _Unwind_SetIP(context:PFPC_Unwind_Context;new_value:PtrUInt); inline;
  98. begin
  99. _Unwind_SetGR(context,15,new_value or (_Unwind_GetGR(context,15) and 1));
  100. end;
  101. function _Unwind_GetIP(context:PFPC_Unwind_Context):PtrUInt;cdecl; inline;
  102. begin
  103. result:=_Unwind_GetGR(context,15) and not(1);
  104. end;
  105. {$else}
  106. function _Unwind_GetGR(context:PFPC_Unwind_Context; index:cint):PtrUInt;cdecl;external;
  107. procedure _Unwind_SetGR(context:PFPC_Unwind_Context; index:cint; new_value:PtrUInt);cdecl;external;
  108. function _Unwind_GetIP(context:PFPC_Unwind_Context):PtrUInt;cdecl;external;
  109. procedure _Unwind_SetIP(context:PFPC_Unwind_Context; new_value:PtrUInt);cdecl;external;
  110. {$endif}
  111. { _Unwind_Backtrace() is a gcc extension that walks the stack and calls the }
  112. { _Unwind_Trace_Fn once per frame until it reaches the bottom of the stack }
  113. { or the _Unwind_Trace_Fn function returns something other than _URC_NO_REASON. }
  114. { }
  115. type
  116. FPC_Unwind_Trace_Fn = function (_para1:PFPC_Unwind_Context; _para2:pointer):FPC_Unwind_Reason_Code;cdecl;
  117. function _Unwind_Backtrace(_para1:FPC_Unwind_Trace_Fn; _para2:pointer):FPC_Unwind_Reason_Code;cdecl;weakexternal;
  118. { _Unwind_GetCFA is a gcc extension that can be called from within a personality }
  119. { handler to get the CFA (stack pointer before call) of current frame. }
  120. { }
  121. function _Unwind_GetCFA(_para1:PFPC_Unwind_Context):PtrUInt;cdecl;weakexternal;
  122. const
  123. DW_EH_PE_absptr = $00;
  124. DW_EH_PE_omit = $ff;
  125. DW_EH_PE_uleb128 = $01;
  126. DW_EH_PE_udata2 = $02;
  127. DW_EH_PE_udata4 = $03;
  128. DW_EH_PE_udata8 = $04;
  129. DW_EH_PE_sleb128 = $09;
  130. DW_EH_PE_sdata2 = $0A;
  131. DW_EH_PE_sdata4 = $0B;
  132. DW_EH_PE_sdata8 = $0C;
  133. DW_EH_PE_signed = $08;
  134. DW_EH_PE_pcrel = $10;
  135. DW_EH_PE_textrel = $20;
  136. DW_EH_PE_datarel = $30;
  137. DW_EH_PE_funcrel = $40;
  138. DW_EH_PE_aligned = $50;
  139. DW_EH_PE_indirect = $80;
  140. {$ifndef PSABIEH_NO_SIZEOF_ENCODED_VALUE}
  141. function FPC_psabieh_size_of_encoded_value(encoding: byte): longint;
  142. begin
  143. if encoding = DW_EH_PE_omit then
  144. exit(0);
  145. case (encoding and 7) of
  146. DW_EH_PE_absptr:
  147. exit(sizeof(pointer));
  148. DW_EH_PE_udata2:
  149. exit(2);
  150. DW_EH_PE_udata4:
  151. exit(4);
  152. DW_EH_PE_udata8:
  153. exit(8);
  154. else
  155. begin
  156. {$ifdef excdebug}
  157. writeln('Unsupported encoding: $', hexstr(encoding,sizeof(encoding)*2));
  158. {$endif}
  159. halt(217);
  160. end;
  161. end
  162. end;
  163. {$endif PSABIEH_NO_SIZEOF_ENCODED_VALUE}
  164. { Given an encoding and an _Unwind_Context, return the base to which
  165. the encoding is relative. This base may then be passed to
  166. read_encoded_value_with_base for use when the _Unwind_Context is
  167. not available. }
  168. function FPC_psabieh_base_of_encoded_value (encoding: byte; context: PFPC_Unwind_Context): PtrUInt;
  169. begin
  170. if encoding = DW_EH_PE_omit then
  171. exit(0);
  172. case (encoding and $70) of
  173. DW_EH_PE_absptr,
  174. DW_EH_PE_pcrel,
  175. DW_EH_PE_aligned:
  176. exit(0);
  177. DW_EH_PE_textrel:
  178. exit(_Unwind_GetTextRelBase(context));
  179. DW_EH_PE_datarel:
  180. exit(_Unwind_GetDataRelBase(context));
  181. DW_EH_PE_funcrel:
  182. exit(_Unwind_GetRegionStart(context));
  183. else
  184. begin
  185. {$ifdef excdebug}
  186. writeln('Unsupported base of encoding: $', hexstr(encoding,sizeof(encoding)*2));
  187. {$endif}
  188. halt(217);
  189. end;
  190. end;
  191. end;
  192. function fpc_read_uleb128 (p: PByte; out val: PTRUInt): PByte;
  193. var
  194. shift: longint;
  195. b: byte;
  196. res: PtrUInt;
  197. begin
  198. shift:=0;
  199. res:=0;
  200. repeat
  201. b:=p^;
  202. inc(p);
  203. res:=res or (PtrUInt(b and $7f) shl shift);
  204. inc(shift,7);
  205. until (b and $80)=0;
  206. val:=res;
  207. result:=p;
  208. end;
  209. function fpc_read_sleb128 (p: PByte; out val: PtrInt): PByte;
  210. var
  211. shift: longint;
  212. b: byte;
  213. res: PtrUInt;
  214. begin
  215. shift:=0;
  216. res:=0;
  217. repeat
  218. b:=p^;
  219. inc(p);
  220. res:=res or (PtrUInt(b and $7f) shl shift);
  221. inc(shift,7);
  222. until (b and $80)=0;
  223. if (shift<8*(sizeof(res))) and
  224. ((b and $40)<>0) then
  225. res:=res or -(PtrUInt(1) shl shift);
  226. val:=PTRInt(res);
  227. result:=p;
  228. end;
  229. function FPC_psabieh_read_encoded_value_with_base (encoding: byte; base: PtrUInt; p: PByte; out val: PtrUInt): PByte;
  230. var
  231. res: PtrUInt;
  232. tmpres: PtrInt;
  233. alignedp: PPtrUint;
  234. begin
  235. if encoding=DW_EH_PE_aligned then
  236. begin
  237. alignedp:=PPtrUint(align(PtrUInt(p),sizeof(PtrUint)));
  238. res:=alignedp^;
  239. result:=PByte(alignedp)+sizeof(PtrUInt);
  240. end
  241. else
  242. begin
  243. case encoding and $0f of
  244. DW_EH_PE_absptr:
  245. begin
  246. res:=unaligned(PPtrUint(p)^);
  247. result:=p+sizeof(PtrUInt);
  248. end;
  249. DW_EH_PE_uleb128:
  250. begin
  251. result:=fpc_read_uleb128(p,res);
  252. end;
  253. DW_EH_PE_sleb128:
  254. begin
  255. result:=fpc_read_sleb128(p,tmpres);
  256. res:=PtrUInt(tmpres);;
  257. end;
  258. DW_EH_PE_udata2:
  259. begin
  260. res:=unaligned(pword(p)^);
  261. result:=p+2;
  262. end;
  263. DW_EH_PE_udata4:
  264. begin
  265. res:=unaligned(pdword(p)^);
  266. result:=p+4;
  267. end;
  268. DW_EH_PE_udata8:
  269. begin
  270. res:=unaligned(pqword(p)^);
  271. result:=p+8;
  272. end;
  273. DW_EH_PE_sdata2:
  274. begin
  275. res:=PtrUInt(unaligned(psmallint(p)^));
  276. result:=p+2;
  277. end;
  278. DW_EH_PE_sdata4:
  279. begin
  280. res:=PtrUInt(unaligned(plongint(p)^));
  281. result:=p+4;
  282. end;
  283. DW_EH_PE_sdata8:
  284. begin
  285. res:=PtrUInt(unaligned(pint64(p)^));
  286. result:=p+8;
  287. end;
  288. else
  289. begin
  290. {$ifdef excdebug}
  291. writeln('Unsupported encoding of value with base: $', hexstr(encoding,sizeof(encoding)*2));
  292. {$endif}
  293. halt(217);
  294. end;
  295. end;
  296. if res<>0 then
  297. begin
  298. if (encoding and $70)=DW_EH_PE_pcrel then
  299. inc(res,PtrUInt(p))
  300. else
  301. inc(res, base);
  302. if (encoding and DW_EH_PE_indirect)<>0 then
  303. res:=PPtrUInt(res)^;
  304. end;
  305. end;
  306. val:=res;
  307. end;
  308. function FPC_psabieh_read_encoded_value (context: PFPC_Unwind_Context; encoding: byte; p: PByte; out val: PtrUInt): PByte; inline;
  309. begin
  310. result:=FPC_psabieh_read_encoded_value_with_base(encoding,FPC_psabieh_base_of_encoded_value(encoding,context),p,val);
  311. end;
  312. type
  313. FPC_psabieh_lsda_header_info = record
  314. Start: PtrUInt;
  315. LPStart: PtrUInt;
  316. ttype_base: PtrUInt;
  317. TType: Pointer;
  318. action_table: pointer;
  319. ttype_encoding: byte;
  320. call_site_encoding: byte;
  321. end;
  322. function FPC_psabieh_parse_lsda_header(context: PFPC_Unwind_Context; p: PByte; out info: FPC_psabieh_lsda_header_info): PByte;
  323. var
  324. tmp: PTRUint;
  325. lpstart_encoding: byte;
  326. begin
  327. if assigned(context) then
  328. info.Start:=_Unwind_GetRegionStart(context)
  329. else
  330. info.Start:=0;
  331. // Find @LPStart, the base to which landing pad offsets are relative.
  332. lpstart_encoding:=p^;
  333. inc(p);
  334. if lpstart_encoding<>DW_EH_PE_omit then
  335. p:=FPC_psabieh_read_encoded_value(context,lpstart_encoding,p,info.LPStart)
  336. else
  337. info.LPStart:=info.Start;
  338. // Find @TType, the base of the handler and exception spec type data.
  339. info.ttype_encoding:=p^;
  340. inc(p);
  341. if info.ttype_encoding<>DW_EH_PE_omit then
  342. begin
  343. p:=fpc_read_uleb128(p,tmp);
  344. info.TType:=p+tmp;
  345. end
  346. else
  347. info.TType:=nil;
  348. // The encoding and length of the call-site table; the action table
  349. // immediately follows.
  350. info.call_site_encoding:=p^;
  351. inc(p);
  352. p:=fpc_read_uleb128(p,tmp);
  353. info.action_table:=p+tmp;
  354. {$ifdef excdebug}
  355. writeln('lsda header');
  356. writeln(' * start: $',hexstr(info.start,sizeof(info.start)*2));
  357. writeln(' * lp_start encoding: $',hexstr(lpstart_encoding,sizeof(lpstart_encoding)*2));
  358. writeln(' * lp_start: $',hexstr(info.LPStart,sizeof(info.LPStart)*2));
  359. writeln(' * ttype_encoding: $',hexstr(info.ttype_encoding,sizeof(info.ttype_encoding)*2));
  360. writeln(' * ttype base: $',hexstr(info.TType));
  361. writeln(' * call_site_encoding: $',hexstr(info.call_site_encoding,sizeof(info.call_site_encoding)*2));
  362. writeln(' * action table: $', hexstr(p),' (offset: ',tmp,')');
  363. {$endif}
  364. result:=p;
  365. end;
  366. {$ifdef __ARM_EABI_UNWINDER__}
  367. function FPC_psabieh_Unwind_decode_target2(ptr: PtrUInt {_Unwind_Word}): PtrUInt {_Unwind_Word}; inline;
  368. begin
  369. result:=PPtrUInt(ptr)^;;
  370. // Zero values are always NULL.
  371. if result<>0 then
  372. begin
  373. {$if defined(linux) or defined(netbsd)}
  374. // Pc-relative indirect.
  375. inc(result,ptr);
  376. result:=PPtrUint(result)^;
  377. {$else}
  378. // Pc-relative pointer.
  379. inc(result,ptr);
  380. {$endif}
  381. end;
  382. end;
  383. {$endif __ARM_EABI_UNWINDER__}
  384. // Return an element from a type table.
  385. {$ifdef __ARM_EABI_UNWINDER__}
  386. function FPC_psabieh_get_ttype_entry(const info: FPC_psabieh_lsda_header_info; i: PtrUInt {_Unwind_Word}): TClass;
  387. var
  388. ptr: PtrUInt {_Unwind_Word};
  389. begin
  390. ptr:=PtrUInt(info.TType)-(i*4);
  391. ptr:=FPC_psabieh_Unwind_decode_target2(ptr);
  392. result:=TClass(ptr);
  393. end;
  394. {$else}
  395. function FPC_psabieh_get_ttype_entry(const info: FPC_psabieh_lsda_header_info; i: PtrUInt): TClass;
  396. var
  397. ptr: PtrUInt;
  398. begin
  399. i:=i*FPC_psabieh_size_of_encoded_value(info.ttype_encoding);
  400. FPC_psabieh_read_encoded_value_with_base(info.ttype_encoding,info.ttype_base,info.TType-i,ptr);
  401. result:=TClass(ptr);
  402. end;
  403. {$endif}
  404. // Return true if THROW_TYPE matches one if the filter types.
  405. function FPC_psabieh_check_exception_spec(const info: FPC_psabieh_lsda_header_info; thrown: TObject; filter_value: PtrInt): boolean;
  406. var
  407. e: PByte;
  408. catch_type: TClass;
  409. tmp: PtrUInt;
  410. begin
  411. e:=info.TType - filter_value - 1;
  412. repeat
  413. e:=fpc_read_uleb128(e,tmp);
  414. // Zero signals the end of the list. If we've not found
  415. // a match by now, then we've failed the specification.
  416. if tmp=0 then
  417. exit(false);
  418. {$ifdef __ARM_EABI_UNWINDER__}
  419. tmp:=FPC_psabieh_Unwind_decode_target2(PtrUInt(e)); {_Unwind_Word}
  420. {$endif}
  421. // Match a ttype entry.
  422. catch_type:=FPC_psabieh_get_ttype_entry(info,tmp);
  423. until thrown is catch_type;
  424. result:=true;
  425. end;
  426. {$ifdef __ARM_EABI_UNWINDER__}
  427. // Save stage1 handler information in the exception object
  428. procedure FPC_psabieh_save_caught_exception(ue_header: PFPC_Unwind_Exception;
  429. context: PFPC_Unwind_Context;
  430. handler_switch_value: longint;
  431. language_specific_data: PByte;
  432. landing_pad: PtrUInt);
  433. begin
  434. with ue_header^.barrier_cache do
  435. begin
  436. sp:=_Unwind_GetGR(context,13);
  437. { bitpattern[0] is assigned but never used in the original code }
  438. bitpattern[1]:=handler_switch_value;
  439. bitpattern[2]:=PtrUInt(language_specific_data);
  440. bitpattern[3]:=landing_pad;
  441. end;
  442. end;
  443. // Restore the catch handler information saved during phase1.
  444. procedure FPC_psabieh_restore_caught_exception(ue_header: PFPC_Unwind_Exception;
  445. out handler_switch_value: longint;
  446. out language_specific_data: PByte;
  447. out landing_pad: PtrUInt);
  448. begin
  449. with ue_header^.barrier_cache do
  450. begin
  451. handler_switch_value:=longint(bitpattern[1]);
  452. language_specific_data:=PByte(bitpattern[2]);
  453. landing_pad:=bitpattern[3];
  454. end;
  455. end;
  456. {$else __ARM_EABI_UNWINDER__}
  457. // Save stage1 handler information in the exception object
  458. procedure FPC_psabieh_save_caught_exception(ue_header: PFPC_Unwind_Exception;
  459. context: PFPC_Unwind_Context;
  460. handler_switch_value: longint;
  461. language_specific_data: PByte;
  462. landing_pad: PtrUInt);
  463. var
  464. xh: PExceptObject;
  465. begin
  466. xh:=FPC_psabieh_GetExceptionWrapper(ue_header);
  467. xh^.handler_switch_value:=handler_switch_value;
  468. xh^.language_specific_data:=language_specific_data;
  469. xh^.landing_pad:=landing_pad;
  470. end;
  471. // Restore the catch handler information saved during phase1.
  472. procedure FPC_psabieh_restore_caught_exception(ue_header: PFPC_Unwind_Exception;
  473. out handler_switch_value: longint;
  474. out language_specific_data: PByte;
  475. out landing_pad: PtrUInt);
  476. var
  477. xh: PExceptObject;
  478. begin
  479. xh:=FPC_psabieh_GetExceptionWrapper(ue_header);
  480. handler_switch_value:=xh^.handler_switch_value;
  481. language_specific_data:=xh^.language_specific_data;
  482. landing_pad:=xh^.landing_pad;
  483. end;
  484. {$endif __ARM_EABI_UNWINDER__}
  485. function FPC_psabieh_find_action_record(const info: FPC_psabieh_lsda_header_info; var p: PByte; const ip: PTRUint; var landing_pad: PtrUInt; var action_record: PByte): boolean;
  486. var
  487. cs_start, cs_len, cs_lp: PtrUint{_Unwind_Ptr};
  488. cs_action: PtrUInt {_Unwind_Word};
  489. begin
  490. result:=false;
  491. {$ifdef excdebug}
  492. writeln('find action record start: p: $',hexstr(p),'; lsda covered code start: $',hexstr(info.Start,sizeof(info.start)*2),'; lsda action table: $',hexstr(info.action_table),'; lsda call site encoding: $',hexstr(info.call_site_encoding,2),'; ip: $', hexstr(ip,sizeof(ip)*2));
  493. {$endif}
  494. while (p<info.action_table) do
  495. begin
  496. // Note that all call-site encodings are "absolute" displacements.
  497. p:=FPC_psabieh_read_encoded_value (nil, info.call_site_encoding, p, cs_start);
  498. p:=FPC_psabieh_read_encoded_value (nil, info.call_site_encoding, p, cs_len);
  499. p:=FPC_psabieh_read_encoded_value (nil, info.call_site_encoding, p, cs_lp);
  500. p:=FPC_read_uleb128 (p, &cs_action);
  501. {$ifdef excdebug}
  502. writeln('find action record: cs_start: $',hexstr(cs_start,sizeof(cs_start)*2),', len: ',cs_len,
  503. ' (ip=$',hexstr(info.Start+cs_start,sizeof(PtrUInt)*2),'...$',hexstr(info.Start+cs_start+cs_len,sizeof(PtrUInt)*2),')',
  504. ', lp: ', cs_lp,' action ofs: ',cs_action);
  505. {$endif}
  506. // The table is sorted, so if we've passed the ip, stop.
  507. if ip<info.Start+cs_start then
  508. p:=info.action_table
  509. else if (ip<(info.Start+cs_start+cs_len)) then
  510. begin
  511. if cs_lp<>0 then
  512. landing_pad:=info.LPStart+cs_lp;
  513. if cs_action<>0 then
  514. action_record:=info.action_table+cs_action-1;
  515. {$ifdef excdebug}
  516. writeln('action record result: action_record: $',hexstr(cs_start,sizeof(cs_start)*2),', len: ',cs_len,', lp: ', cs_lp,
  517. ',landing_pad: $',hexstr(landing_pad,sizeof(landing_pad)*2));
  518. {$endif}
  519. result:=true;
  520. exit;
  521. end;
  522. end;
  523. {$ifdef excdebug}
  524. writeln('find action record failed');
  525. {$endif}
  526. end;
  527. // Return true if the filter spec is empty, ie throw().
  528. function fpc_psabieh_empty_exception_spec(const info: FPC_psabieh_lsda_header_info; const filter_value: PtrInt {_Unwind_Sword}): boolean;
  529. var
  530. e: PByte;
  531. tmp: PtrUInt;
  532. begin
  533. e:=PByte(info.ttype - filter_value - 1);
  534. e:=fpc_read_uleb128(e,tmp);
  535. result:=tmp = 0;
  536. end;
  537. type
  538. FPC_psabieh_found_handler_type = (
  539. found_nothing,
  540. found_terminate,
  541. found_cleanup,
  542. found_handler
  543. );
  544. function FPC_psabieh_find_handler(const info: FPC_psabieh_lsda_header_info; const foreign_exception: boolean; actions: FPC_Unwind_Action; thrown: TObject; var action_record: PByte; var handler_switch_value: longint): FPC_psabieh_found_handler_type;
  545. var
  546. ar_filter, ar_disp: PtrInt;
  547. catch_type: TClass;
  548. throw_type: TOBject;
  549. saw_cleanup, saw_handler: boolean;
  550. p: PByte;
  551. begin
  552. saw_cleanup:=false;
  553. saw_handler:=false;
  554. // During forced unwinding, we only run cleanups. With a foreign
  555. // exception class, there's no exception type.
  556. if ((actions and FPC_UA_FORCE_UNWIND)<>0) or
  557. foreign_exception then
  558. throw_type:=nil
  559. else
  560. throw_type:=thrown;
  561. while true do
  562. begin
  563. p:=action_record;
  564. p:=fpc_read_sleb128(p,ar_filter);
  565. fpc_read_sleb128(p,ar_disp);
  566. if ar_filter=0 then
  567. begin
  568. // Zero filter values are cleanups.
  569. saw_cleanup:=true;
  570. end
  571. else if ar_filter>0 then
  572. begin
  573. // Positive filter values are handlers.
  574. catch_type:=FPC_psabieh_get_ttype_entry(info,ar_filter);
  575. // Null catch type is a catch-all handler; we can catch foreign
  576. // exceptions with this. Otherwise we must match types.
  577. if not assigned(catch_type) or
  578. (assigned(throw_type) and
  579. (throw_type is catch_type)) then
  580. begin
  581. saw_handler:=true;
  582. break;
  583. end
  584. end
  585. else
  586. begin
  587. // Negative filter values are exception specifications.
  588. // ??? How do foreign exceptions fit in? As far as I can
  589. // see we can't match because there's no __cxa_exception
  590. // object to stuff bits in for __cxa_call_unexpected to use.
  591. // Allow them iff the exception spec is non-empty. I.e.
  592. // a throw() specification results in __unexpected.
  593. if (assigned(throw_type) and
  594. not FPC_psabieh_check_exception_spec(info,thrown,ar_filter)) or
  595. (not assigned(throw_type) and
  596. FPC_psabieh_empty_exception_spec(info,ar_filter)) then
  597. begin
  598. saw_handler:=true;
  599. break;
  600. end;
  601. end;
  602. if ar_disp=0 then
  603. break;
  604. action_record:=p+ar_disp;
  605. end;
  606. if saw_handler then
  607. begin
  608. handler_switch_value:=ar_filter;
  609. result:=found_handler;
  610. end
  611. else
  612. begin
  613. if saw_cleanup then
  614. result:=found_cleanup
  615. else
  616. result:=found_nothing;
  617. end;
  618. end;
  619. {$ifdef FPC_PSABIEH_CPLUSPLUSSUPPORT}
  620. procedure __gxx_personality_v0(version: cint; actions: FPC_Unwind_Action; exceptionClass: cuint64; libunwind_exception: PFPC_Unwind_Exception; context: PFPC_Unwind_Context); cdecl; external;
  621. {$endif FPC_PSABIEH_CPLUSPLUSSUPPORT}
  622. {$ifdef __ARM_EABI_UNWINDER__}
  623. function continue_unwinding(libunwind_exception: PFPC_Unwind_Exception; context: PFPC_Unwind_Context): FPC_Unwind_Reason_Code; inline;
  624. begin
  625. if __gnu_unwind_frame(libunwind_exception, context)<>FPC_URC_OK then
  626. result:=FPC_URC_FAILURE
  627. else
  628. result:=FPC_URC_CONTINUE_UNWIND;
  629. end;
  630. function _FPC_psabieh_personality_v0(state: FPC_Unwind_State; libunwind_exception: PFPC_Unwind_Exception; context: PFPC_Unwind_Context): FPC_Unwind_Reason_Code; cdecl;
  631. {$else}
  632. function continue_unwinding(libunwind_exception: PFPC_Unwind_Exception; context: PFPC_Unwind_Context): FPC_Unwind_Reason_Code; inline;
  633. begin
  634. result:=FPC_URC_CONTINUE_UNWIND;
  635. end;
  636. function _FPC_psabieh_personality_v0(version: longint; actions: FPC_Unwind_Action; exceptionClass: qword; libunwind_exception: PFPC_Unwind_Exception; context: PFPC_Unwind_Context): FPC_Unwind_Reason_Code; cdecl;
  637. {$endif}
  638. var
  639. WrappedException: PExceptObject;
  640. found_type: FPC_psabieh_found_handler_type;
  641. info: FPC_psabieh_lsda_header_info;
  642. language_specific_data: PByte;
  643. action_record: PByte;
  644. p: PByte;
  645. landing_pad, ip: PtrUInt; { _Unwind_Ptr }
  646. handler_switch_value: longint;
  647. foreign_exception: boolean;
  648. {$ifdef __ARM_EABI_UNWINDER__}
  649. actions: FPC_Unwind_Action;
  650. {$endif}
  651. begin
  652. {$ifdef __ARM_EABI_UNWINDER__}
  653. { convert the state flags to FPC_Unwind_Action flags so we can share the rest of the code }
  654. case (state and FPC_US_ACTION_MASK) of
  655. FPC_US_VIRTUAL_UNWIND_FRAME:
  656. begin
  657. actions:=FPC_UA_SEARCH_PHASE;
  658. end;
  659. FPC_US_UNWIND_FRAME_STARTING:
  660. begin
  661. actions:=FPC_UA_CLEANUP_PHASE;
  662. if ((state and FPC_US_FORCE_UNWIND)<>0) and
  663. (libunwind_exception^.barrier_cache.sp=_Unwind_GetGR(context,13)) then
  664. actions:=actions or FPC_UA_HANDLER_FRAME;
  665. end;
  666. FPC_US_UNWIND_FRAME_RESUME:
  667. begin
  668. result:=continue_unwinding(libunwind_exception,context);
  669. exit;
  670. end;
  671. end;
  672. actions:=actions or (state and FPC_US_FORCE_UNWIND);
  673. // The dwarf unwinder assumes the context structure holds things like the
  674. // function and LSDA pointers. The ARM implementation caches these in
  675. // the exception header (UCB). To avoid rewriting everything we make the
  676. // virtual IP register point at the UCB.
  677. ip:=PtrUInt(libunwind_exception);
  678. _Unwind_SetGR(context, 12, ip);
  679. { foreign exception type -> let c++ runtime handle it }
  680. foreign_exception:=libunwind_exception^.exception_class<>FPC_psabieh_exceptionClass_ID.u;
  681. {$else __ARM_EABI_UNWINDER__}
  682. { unsupported version -> failure }
  683. if version<>1 then
  684. begin
  685. result:=FPC_URC_FATAL_PHASE1_ERROR;
  686. exit;
  687. end;
  688. { foreign exception type -> let c++ runtime handle it }
  689. foreign_exception:=exceptionClass<>FPC_psabieh_exceptionClass_ID.u;
  690. {$endif __ARM_EABI_UNWINDER__}
  691. {$ifdef FPC_PSABIEH_CPLUSPLUSSUPPORT}
  692. if foreign_exception then
  693. begin
  694. result:=__gxx_personality_v0(version, actions, exceptionClass, libunwind_exception, context)
  695. exit;
  696. end;
  697. {$endif FPC_PSABIEH_CPLUSPLUSSUPPORT}
  698. WrappedException:=FPC_psabieh_GetExceptionWrapper(libunwind_exception);
  699. {$ifdef excdebug}
  700. writeln('Personality (version = ',version,', actions = $',hexstr(actions,4),') started for wrapper ',hexstr(WrappedException),' = fpc exc ',hexstr(WrappedException^.FObject),
  701. ', refcount is now ',WrappedException^.refcount);
  702. writeln(' ip=$',hexstr(_Unwind_GetIP(context),sizeof(pointer)*2));
  703. {$endif}
  704. // Shortcut for phase 2 found handler for domestic exception.
  705. if (actions=(FPC_UA_CLEANUP_PHASE or FPC_UA_HANDLER_FRAME)) and
  706. not foreign_exception then
  707. begin
  708. {$ifdef excdebug}
  709. writeln('restoring caught exception');
  710. {$endif}
  711. FPC_psabieh_restore_caught_exception(libunwind_exception,handler_switch_value,
  712. language_specific_data,landing_pad);
  713. {$ifdef excdebug}
  714. writeln('restoring caught exception, landing_pad = $',hexstr(landing_pad,sizeof(landing_pad)*2));
  715. {$endif}
  716. if landing_pad<>0 then
  717. found_type:=found_handler
  718. else
  719. found_type:=found_terminate;
  720. end
  721. else
  722. begin
  723. language_specific_data:=PByte(_Unwind_GetLanguageSpecificData(context));
  724. // If no LSDA, then there are no handlers or cleanups.
  725. if not assigned(language_specific_data) then
  726. begin
  727. {$ifdef excdebug}
  728. writeln('did not find lsda for ip $',hexstr(_Unwind_GetIP(context),sizeof(pointer)*2));
  729. {$endif}
  730. exit(continue_unwinding(libunwind_exception,context));
  731. end;
  732. // Parse the LSDA header.
  733. p:=FPC_psabieh_parse_lsda_header(context,language_specific_data,info);
  734. info.ttype_base:=FPC_psabieh_base_of_encoded_value(info.ttype_encoding,context);
  735. ip:=_Unwind_GetIP(context);
  736. dec(ip);
  737. landing_pad:=0;
  738. action_record:=nil;
  739. handler_switch_value:=0;
  740. // Search the call-site table for the action associated with this IP.
  741. if FPC_psabieh_find_action_record(info,p,ip,landing_pad,action_record) then
  742. begin
  743. {$ifdef excdebug}
  744. writeln('found action record for ip ',hexstr(_Unwind_GetIP(context),sizeof(pointer)*2));
  745. {$endif}
  746. if landing_pad=0 then
  747. begin
  748. // If ip is present, and has a null landing pad, there are
  749. // no cleanups or handlers to be run.
  750. found_type:=found_nothing;
  751. end
  752. else if action_record=nil then
  753. begin
  754. // If ip is present, has a non-null landing pad, and a null
  755. // action table offset, then there are only cleanups present.
  756. // Cleanups use a zero switch value, as set above.
  757. found_type:=found_cleanup;
  758. end
  759. else
  760. begin
  761. // Otherwise we have a catch handler or exception specification.
  762. found_type:=FPC_psabieh_find_handler(info,foreign_exception,actions,WrappedException^.FObject,action_record,handler_switch_value);
  763. end
  764. end
  765. else
  766. begin
  767. // If ip is not present in the table, call terminate. This is for
  768. // a destructor inside a cleanup, or a library routine the compiler
  769. // was not expecting to throw.
  770. found_type:=found_terminate;
  771. end;
  772. {$ifdef excdebug}
  773. writeln('find_handler: ',found_type);
  774. {$endif}
  775. if found_type=found_nothing then
  776. exit(continue_unwinding(libunwind_exception,context));
  777. if (actions and FPC_UA_SEARCH_PHASE)<>0 then
  778. begin
  779. if found_type=found_cleanup then
  780. exit(continue_unwinding(libunwind_exception,context));
  781. if not foreign_exception then
  782. begin
  783. {$ifdef excdebug}
  784. writeln('saving native exception: $',hexstr(landing_pad,sizeof(landing_pad)*2));
  785. {$endif}
  786. // For domestic exceptions, we cache data from phase 1 for phase 2.
  787. FPC_psabieh_save_caught_exception(libunwind_exception,context,
  788. handler_switch_value,language_specific_data,
  789. landing_pad);
  790. end;
  791. exit(FPC_URC_HANDLER_FOUND);
  792. end;
  793. end;
  794. if ((actions and FPC_UA_FORCE_UNWIND)<>0) or
  795. foreign_exception then
  796. begin
  797. if found_type=found_terminate then
  798. begin
  799. {$ifdef excdebug}
  800. writeln('foreign exception or force unwind, and found type = found terminate; actions = $',hexstr(actions,sizeof(actions)*2),'; foreign exception ', foreign_exception);
  801. {$endif}
  802. RunError(217);
  803. end
  804. { can only perform cleanups when force-unwinding }
  805. else if handler_switch_value<0 then
  806. begin
  807. {$ifdef excdebug}
  808. writeln('foreign exception or force unwind, handler_switch_value < 0: ', handler_switch_value);
  809. {$endif}
  810. RunError(217)
  811. end
  812. end
  813. else
  814. begin
  815. if found_type=found_terminate then
  816. begin
  817. {$ifdef excdebug}
  818. writeln('native exception and no force unwind, and force_terminate');
  819. {$endif}
  820. RunError(217);
  821. end
  822. else if handler_switch_value<0 then
  823. begin
  824. { C++ calls __cxa_call_unexpected in this case }
  825. {$ifdef excdebug}
  826. writeln('native exception and no force unwind, and handler_switch_value<0: ', handler_switch_value);
  827. {$endif}
  828. RunError(217);
  829. end;
  830. end;
  831. { For targets with pointers smaller than the word size, we must extend the
  832. pointer, and this extension is target dependent. }
  833. {$if sizeof(pointer)<>sizeof(SizeInt)}
  834. {$error Add support for extending pointer values}
  835. {$endif}
  836. {$ifdef excdebug}
  837. writeln('returning exception $',hexstr(libunwind_exception),' with switch value ',handler_switch_value);
  838. {$endif}
  839. _Unwind_SetGR(context,fpc_eh_return_data_regno(0),PtrUInt(libunwind_exception));
  840. _Unwind_SetGR (context,fpc_eh_return_data_regno(1),handler_switch_value);
  841. _Unwind_SetIP(context,landing_pad);
  842. result:=FPC_URC_INSTALL_CONTEXT;
  843. end;
  844. //////////////////////////////
  845. ///// Raising an exception
  846. //////////////////////////////
  847. procedure FPC_psabieh_ExceptionCleanUp(reason: FPC_Unwind_Reason_Code; exc:PFPC_Unwind_Exception); cdecl;
  848. var
  849. ExceptWrapper: PExceptObject;
  850. begin
  851. // If we haven't been caught by a foreign handler, then this is
  852. // some sort of unwind error. In that case just die immediately.
  853. // _Unwind_DeleteException in the HP-UX IA64 libunwind library
  854. // returns _URC_NO_REASON and not _URC_FOREIGN_EXCEPTION_CAUGHT
  855. // like the GCC _Unwind_DeleteException function does.
  856. if (reason<>FPC_URC_FOREIGN_EXCEPTION_CAUGHT) and
  857. (reason<>FPC_URC_NO_REASON) then
  858. begin
  859. {$ifdef excdebug}
  860. writeln('exception cleanup and reason not foreign exception or no reason, reason = $',hexstr(reason,sizeof(reason)*2));
  861. {$endif}
  862. halt(217);
  863. end;
  864. ExceptWrapper:=FPC_psabieh_GetExceptionWrapper(exc);
  865. {$ifdef excdebug}
  866. writeln('exception cleanup: deleting wrapper ',hexstr(ExceptWrapper),' and fpc exception ',hexstr(ExceptWrapper^.FObject));
  867. {$endif}
  868. ExceptWrapper^.FObject.free;
  869. ExceptWrapper^.FObject:=nil;
  870. if assigned(ExceptWrapper^.frames) then
  871. freemem(ExceptWrapper^.frames);
  872. Dispose(ExceptWrapper);
  873. end;
  874. function PushExceptObject(Obj : TObject; AnAddr : CodePointer; AFrame : Pointer): PExceptObject; forward;
  875. {$define FPC_SYSTEM_HAS_RAISEEXCEPTION}
  876. procedure fpc_RaiseException(Obj: TObject; AnAddr: CodePointer; AFrame: Pointer); compilerproc;
  877. var
  878. _ExceptObjectStack : PExceptObject;
  879. _ExceptAddrstack : PExceptAddr;
  880. ExceptWrapper: PExceptObject;
  881. RaiseResult: FPC_Unwind_Reason_Code;
  882. begin
  883. {$ifdef excdebug}
  884. writeln ('In psabieh RaiseException for object ',hexstr(obj),' of class type ',obj.classname);
  885. {$endif}
  886. if ExceptTryLevel<>0 then
  887. begin
  888. {$ifdef excdebug}
  889. writeln('exception while raising exception, aborting');
  890. {$endif}
  891. Halt(217);
  892. end;
  893. ExceptTryLevel:=1;
  894. ExceptWrapper:=PushExceptObject(Obj,AnAddr,AFrame);
  895. ExceptWrapper^.unwind_exception.exception_class:=FPC_psabieh_exceptionClass_ID.u;
  896. ExceptWrapper^.unwind_exception.exception_cleanup:=@FPC_psabieh_ExceptionCleanUp;
  897. { if PushExceptObject causes another exception, the following won't be executed,
  898. causing halt upon entering this routine recursively. }
  899. ExceptTryLevel:=0;
  900. _ExceptObjectStack:=ExceptObjectStack;
  901. if (RaiseProc <> nil) and (_ExceptObjectStack <> nil) then
  902. with _ExceptObjectStack^ do
  903. RaiseProc(FObject,Addr,FrameCount,Frames);
  904. RaiseResult:=_Unwind_RaiseException(@ExceptWrapper^.unwind_exception);
  905. // should never return
  906. {$ifdef excdebug}
  907. writeln('_Unwind_RaiseException returned: ',RaiseResult);
  908. {$endif}
  909. Halt(217);
  910. end;
  911. {$ifdef FPC_PSABIEH_CPLUSPLUSSUPPORT}
  912. function __cxa_begin_catch(exc:PFPC_Unwind_Exception): pointer; cdecl; external;
  913. {$endif FPC_PSABIEH_CPLUSPLUSSUPPORT}
  914. function FPC_psabi_begin_catch(exc:PFPC_Unwind_Exception): pointer; cdecl; compilerproc;
  915. var
  916. ExceptWrapper: PExceptObject;
  917. _ExceptObjectStack : PExceptObject;
  918. count: longint;
  919. begin
  920. {$ifdef excdebug}
  921. writeln('start begin_catch unwind exception ',hexstr(exc));
  922. {$endif}
  923. _ExceptObjectStack:=ExceptObjectStack;
  924. // hand off foreign exceptions to the C++ runtime
  925. if exc^.exception_class<>FPC_psabieh_exceptionClass_ID.u then
  926. begin
  927. // Can't link foreign exceptions with our stack
  928. if assigned(_ExceptObjectStack) then
  929. begin
  930. {$ifdef excdebug}
  931. writeln('begin catch for nested foreign exception');
  932. {$endif}
  933. halt(217);
  934. end;
  935. // This is a wrong conversion, but as long as afterwards we only access
  936. // fields of PFPC_Unwind_Exception, it's fine
  937. _ExceptObjectStack:=FPC_psabieh_GetExceptionWrapper(exc);
  938. {$ifdef FPC_PSABIEH_CPLUSPLUSSUPPORT}
  939. result:=__cxa_begin_catch(exc);
  940. {$else}
  941. // ??? No sensible value to return; we don't know what the
  942. // object is, much less where it is in relation to the header.
  943. result:=nil;
  944. {$endif}
  945. exit;
  946. end;
  947. ExceptWrapper:=FPC_psabieh_GetExceptionWrapper(exc);
  948. count:=ExceptWrapper^.refcount;
  949. // Count is less than zero if this exception was rethrown from an
  950. // immediately enclosing region.
  951. if count < 0 then
  952. count:=-count+1
  953. else
  954. inc(count);
  955. ExceptWrapper^.refcount:=count;
  956. // globals->uncaughtExceptions -= 1;
  957. if _ExceptObjectStack<>ExceptWrapper then
  958. begin
  959. ExceptWrapper^.Next:=_ExceptObjectStack;
  960. ExceptObjectStack:=ExceptWrapper;
  961. end;
  962. {$ifdef excdebug}
  963. writeln('stop begin_catch for wrapper ',hexstr(ExceptWrapper),' = fpc exc ',hexstr(ExceptWrapper^.FObject),', refcount is now ',count);
  964. {$endif}
  965. result:= ExceptWrapper^.FObject;
  966. {$ifdef __ARM_EABI_UNWINDER__}
  967. _Unwind_Complete(exc);
  968. {$endif}
  969. end;
  970. {$ifdef FPC_PSABIEH_CPLUSPLUSSUPPORT}
  971. procedure __cxa_end_catch; cdecl; external;
  972. {$endif FPC_PSABIEH_CPLUSPLUSSUPPORT}
  973. procedure FPC_psabi_end_catch; cdecl; compilerproc;
  974. var
  975. _ExceptObjectStack: PExceptObject;
  976. refcount: longint;
  977. begin
  978. _ExceptObjectStack:=ExceptObjectStack;
  979. {$ifdef excdebug}
  980. writeln('start end_catch unwind exception ',hexstr(@_ExceptObjectStack^.unwind_exception));
  981. {$endif}
  982. // A rethrow of a foreign exception will be removed from the
  983. // the exception stack immediately by __cxa_rethrow -> stack could be empty here
  984. if not assigned(_ExceptObjectStack) then
  985. exit;
  986. // Pass foreign exception to the C++ runtime
  987. if _ExceptObjectStack^.unwind_exception.exception_class<>FPC_psabieh_exceptionClass_ID.u then
  988. begin
  989. { remove foreign exception; since we never link multiple foreign
  990. exceptions, we know the stack is now empty }
  991. ExceptObjectStack:=nil;
  992. {$ifdef FPC_PSABIEH_CPLUSPLUSSUPPORT}
  993. __cxa_end_catch();
  994. {$else}
  995. _Unwind_DeleteException(@_ExceptObjectStack^.unwind_exception);
  996. {$endif}
  997. exit;
  998. end;
  999. refcount:=_ExceptObjectStack^.refcount;
  1000. {$ifdef excdebug}
  1001. writeln('middle end_catch for wrapper ',hexstr(_ExceptObjectStack),' = fpc exception ',hexstr(_ExceptObjectStack^.FObject),' with refcount ',refcount);
  1002. {$endif}
  1003. if refcount<0 then
  1004. begin
  1005. { Can happen in the original glibc code, but not for us. When re-raising an
  1006. exception, we always immediately do this to an outer frame }
  1007. halt(217);
  1008. end
  1009. else
  1010. begin
  1011. dec(refcount);
  1012. {$ifdef excdebug}
  1013. writeln('stop end_catch, not rethrown, new refcount: ',refcount);
  1014. {$endif}
  1015. if refcount=0 then
  1016. begin
  1017. // Handling for this exception is complete. Destroy the object.
  1018. ExceptObjectStack:=_ExceptObjectStack^.next;
  1019. _Unwind_DeleteException(@_ExceptObjectStack^.unwind_exception);
  1020. exit;
  1021. end
  1022. else if refcount<0 then
  1023. begin
  1024. // A bug in the exception handling library or compiler.
  1025. {$ifdef excdebug}
  1026. writeln('refcount for exception is negative in end catch');
  1027. {$endif}
  1028. RunError(217);
  1029. end;
  1030. end;
  1031. _ExceptObjectStack^.refcount:=refcount;
  1032. end;
  1033. {$ifdef FPC_PSABIEH_CPLUSPLUSSUPPORT}
  1034. procedure __cxa_rethrow; cdecl; external; noreturn;
  1035. {$endif FPC_PSABIEH_CPLUSPLUSSUPPORT}
  1036. {$define FPC_SYSTEM_HAS_RERAISE}
  1037. procedure fpc_ReRaise; [public,alias:'FPC_RERAISE']; compilerproc;
  1038. var
  1039. _ExceptObjectStack: PExceptObject;
  1040. refcount: longint;
  1041. reraise_error: FPC_Unwind_Reason_Code;
  1042. begin
  1043. _ExceptObjectStack:=ExceptObjectStack;
  1044. // globals->uncaughtExceptions += 1;
  1045. {$ifdef excdebug}
  1046. writeln('start reraise for wrapper ',hexstr(_ExceptObjectStack));
  1047. {$endif}
  1048. // Watch for luser rethrowing with no active exception.
  1049. if assigned(_ExceptObjectStack) then
  1050. begin
  1051. // Tell __cxa_end_catch this is a rethrow.
  1052. if _ExceptObjectStack^.unwind_exception.exception_class<>FPC_psabieh_exceptionClass_ID.u then
  1053. {$ifdef FPC_PSABIEH_CPLUSPLUSSUPPORT}
  1054. begin
  1055. { remove foreign exception; since we never link multiple foreign
  1056. exceptions, we know the stack is now empty }
  1057. ExceptObjectStack:=nil;
  1058. __cxa_rethrow;
  1059. { should never be reached }
  1060. RunError(217);
  1061. end
  1062. {$endif FPC_PSABIEH_CPLUSPLUSSUPPORT}
  1063. else
  1064. begin
  1065. { reraise has to reset the refcount, this is also what the
  1066. generic exception handling does }
  1067. _ExceptObjectStack^.refcount := 0;
  1068. end;
  1069. {$ifdef excdebug}
  1070. writeln('Stop reraise, new refcount = ',_ExceptObjectStack^.refcount);
  1071. {$endif}
  1072. // #ifdef _GLIBCXX_SJLJ_EXCEPTIONS
  1073. // _Unwind_SjLj_Resume_or_Rethrow (&header->unwindHeader);
  1074. // #else
  1075. // #if defined(_LIBUNWIND_STD_ABI)
  1076. // _Unwind_RaiseException (@_ExceptObjectStack^.unwind_exception);
  1077. // #else
  1078. reraise_error:=_Unwind_Resume_or_Rethrow (@_ExceptObjectStack^.unwind_exception);
  1079. {$ifdef excdebug}
  1080. writeln('reraise failed, error = ',reraise_error);
  1081. {$endif}
  1082. // #endif
  1083. // #endif
  1084. // Some sort of unwinding error.
  1085. RunError(217);
  1086. end;
  1087. RunError(217);
  1088. end;
  1089. {$define FPC_SYSTEM_HAS_RESUME}
  1090. procedure fpc_Resume(exception_object: PFPC_Unwind_Exception); [public,alias:'FPC_RESUME']; compilerproc; assembler; nostackframe;
  1091. asm
  1092. popl %ecx
  1093. pushl %eax
  1094. pushl %ecx
  1095. jmp _Unwind_Resume
  1096. end;
  1097. {$define FPC_SYSTEM_HAS_RAISENESTED}
  1098. procedure fpc_raise_nested;compilerproc;
  1099. var
  1100. hp, _ExceptObjectStack: PExceptObject;
  1101. begin
  1102. _ExceptObjectStack:=ExceptObjectStack;
  1103. if not(assigned(_ExceptObjectStack)) or
  1104. not(assigned(_ExceptObjectStack^.next)) then
  1105. begin
  1106. {$ifdef excdebug}
  1107. writeln ('raise_nested: At end of ExceptionObjectStack');
  1108. {$endif}
  1109. halt(1);
  1110. end;
  1111. if _ExceptObjectStack^.unwind_exception.exception_class<>FPC_psabieh_exceptionClass_ID.u then
  1112. begin
  1113. {$ifdef excdebug}
  1114. writeln ('raise_nested: top of stack contains foreign exception');
  1115. {$endif}
  1116. halt(1);
  1117. end;
  1118. hp:=_ExceptObjectStack^.next;
  1119. _ExceptObjectStack^.next:=hp^.next;
  1120. {$ifdef excdebug}
  1121. writeln('raise_nested: raising nested wrapper ',hexstr(_ExceptObjectStack),' = fpc exception ',hexstr(_ExceptObjectStack^.FObject),' with refcount ',_ExceptObjectStack^.refcount{,' (will increase to ',_ExceptObjectStack^.refcount+1,')'});
  1122. writeln('raise_nested: previous exception ',hexstr(hp),' = fpc exception ',hexstr(hp^.FObject),' with refcount ',hp^.refcount,' (will delete if refcount = 1, otherwise decrease to',hp^.refcount-1,')');
  1123. {$endif}
  1124. if hp^.refcount=1 then
  1125. { we need to free the original exception object if its refcount=1
  1126. (means it was not acquired, only refcount increase by begin_catch) }
  1127. _Unwind_DeleteException(@hp^.unwind_exception)
  1128. else
  1129. dec(hp^.refcount);
  1130. _Unwind_RaiseException(@_ExceptObjectStack^.unwind_exception);
  1131. RunError(217);
  1132. end;
  1133. procedure FPC_DummyPotentialRaise; nostackframe; assembler;
  1134. asm
  1135. end;