psabieh.inc 43 KB

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