except.inc 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by Michael Van Canneyt
  4. member of the Free Pascal development team
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {****************************************************************************
  12. Exception support
  13. ****************************************************************************}
  14. Const
  15. { Type of exception. Currently only one. }
  16. FPC_EXCEPTION = 1;
  17. { types of frames for the exception address stack }
  18. cExceptionFrame = 1;
  19. cFinalizeFrame = 2;
  20. Type
  21. PExceptAddr = ^TExceptAddr;
  22. TExceptAddr = record
  23. buf : pjmp_buf;
  24. next : PExceptAddr;
  25. frametype : Longint;
  26. end;
  27. TExceptObjectClass = Class of TObject;
  28. Const
  29. CatchAllExceptions : PtrInt = -1;
  30. ThreadVar
  31. ExceptAddrStack : PExceptAddr;
  32. ExceptObjectStack : PExceptObject;
  33. Function RaiseList : PExceptObject;
  34. begin
  35. RaiseList:=ExceptObjectStack;
  36. end;
  37. function AcquireExceptionObject: Pointer;
  38. var
  39. _ExceptObjectStack : PExceptObject;
  40. begin
  41. _ExceptObjectStack:=ExceptObjectStack;
  42. If _ExceptObjectStack<>nil then
  43. begin
  44. Inc(_ExceptObjectStack^.refcount);
  45. AcquireExceptionObject := _ExceptObjectStack^.FObject;
  46. end
  47. else
  48. RunError(231);
  49. end;
  50. procedure ReleaseExceptionObject;
  51. var
  52. _ExceptObjectStack : PExceptObject;
  53. begin
  54. _ExceptObjectStack:=ExceptObjectStack;
  55. If _ExceptObjectStack <> nil then
  56. begin
  57. if _ExceptObjectStack^.refcount > 0 then
  58. Dec(_ExceptObjectStack^.refcount);
  59. end
  60. else
  61. RunError(231);
  62. end;
  63. Function fpc_PushExceptAddr (Ft: Longint;_buf,_newaddr : pointer): PJmp_buf ;
  64. [Public, Alias : 'FPC_PUSHEXCEPTADDR'];compilerproc;
  65. var
  66. _ExceptAddrstack : ^PExceptAddr;
  67. begin
  68. {$ifdef excdebug}
  69. writeln ('In PushExceptAddr');
  70. {$endif}
  71. _ExceptAddrstack:=@ExceptAddrstack;
  72. PExceptAddr(_newaddr)^.Next:=_ExceptAddrstack^;
  73. _ExceptAddrStack^:=PExceptAddr(_newaddr);
  74. PExceptAddr(_newaddr)^.Buf:=PJmp_Buf(_buf);
  75. PExceptAddr(_newaddr)^.FrameType:=ft;
  76. result:=PJmp_Buf(_buf);
  77. end;
  78. Procedure fpc_PushExceptObj (Obj : TObject; AnAddr,AFrame : Pointer);
  79. [Public, Alias : 'FPC_PUSHEXCEPTOBJECT']; compilerproc;
  80. var
  81. Newobj : PExceptObject;
  82. _ExceptObjectStack : ^PExceptObject;
  83. framebufsize,
  84. framecount : longint;
  85. frames : PPointer;
  86. prev_frame,
  87. curr_frame,
  88. caller_frame,
  89. caller_addr : Pointer;
  90. begin
  91. {$ifdef excdebug}
  92. writeln ('In PushExceptObject');
  93. {$endif}
  94. _ExceptObjectStack:=@ExceptObjectStack;
  95. If _ExceptObjectStack^=Nil then
  96. begin
  97. New(_ExceptObjectStack^);
  98. _ExceptObjectStack^^.Next:=Nil;
  99. end
  100. else
  101. begin
  102. New(NewObj);
  103. NewObj^.Next:=_ExceptObjectStack^;
  104. _ExceptObjectStack^:=NewObj;
  105. end;
  106. with _ExceptObjectStack^^ do
  107. begin
  108. FObject:=Obj;
  109. Addr:=AnAddr;
  110. refcount:=0;
  111. end;
  112. { Backtrace }
  113. curr_frame:=AFrame;
  114. prev_frame:=get_frame;
  115. frames:=nil;
  116. framebufsize:=0;
  117. framecount:=0;
  118. while (framecount<RaiseMaxFrameCount) and (curr_frame > prev_frame) and
  119. (curr_frame<(StackBottom + StackLength)) do
  120. Begin
  121. caller_addr := get_caller_addr(curr_frame);
  122. caller_frame := get_caller_frame(curr_frame);
  123. if (caller_addr=nil) or
  124. (caller_frame=nil) then
  125. break;
  126. if (framecount>=framebufsize) then
  127. begin
  128. inc(framebufsize,16);
  129. reallocmem(frames,framebufsize*sizeof(pointer));
  130. end;
  131. frames[framecount]:=caller_addr;
  132. inc(framecount);
  133. prev_frame:=curr_frame;
  134. curr_frame:=caller_frame;
  135. End;
  136. _ExceptObjectStack^^.framecount:=framecount;
  137. _ExceptObjectStack^^.frames:=frames;
  138. end;
  139. { make it avalable for local use }
  140. Procedure fpc_PushExceptObj (Obj : TObject; AnAddr,AFrame : Pointer); [external name 'FPC_PUSHEXCEPTOBJECT'];
  141. Procedure DoUnHandledException;
  142. var
  143. _ExceptObjectStack : PExceptObject;
  144. begin
  145. _ExceptObjectStack:=ExceptObjectStack;
  146. If (ExceptProc<>Nil) and (_ExceptObjectStack<>Nil) then
  147. with _ExceptObjectStack^ do
  148. begin
  149. TExceptProc(ExceptProc)(FObject,Addr,FrameCount,Frames);
  150. halt(217)
  151. end;
  152. if erroraddr = nil then
  153. RunError(217)
  154. else
  155. {$ifdef FPC_LIMITED_EXITCODE}
  156. if errorcode > maxExitCode then
  157. halt(255)
  158. else
  159. {$endif FPC_LIMITED_EXITCODE}
  160. halt(errorcode);
  161. end;
  162. Function fpc_RaiseException (Obj : TObject; AnAddr,AFrame : Pointer) : TObject;[Public, Alias : 'FPC_RAISEEXCEPTION']; compilerproc;
  163. var
  164. _ExceptObjectStack : PExceptObject;
  165. _ExceptAddrstack : PExceptAddr;
  166. begin
  167. {$ifdef excdebug}
  168. writeln ('In RaiseException');
  169. {$endif}
  170. fpc_Raiseexception:=nil;
  171. fpc_PushExceptObj(Obj,AnAddr,AFrame);
  172. _ExceptAddrstack:=ExceptAddrStack;
  173. If _ExceptAddrStack=Nil then
  174. DoUnhandledException;
  175. _ExceptObjectStack:=ExceptObjectStack;
  176. if (RaiseProc <> nil) and (_ExceptObjectStack <> nil) then
  177. with _ExceptObjectStack^ do
  178. RaiseProc(FObject,Addr,FrameCount,Frames);
  179. longjmp(_ExceptAddrStack^.Buf^,FPC_Exception);
  180. end;
  181. Procedure fpc_PopAddrStack;[Public, Alias : 'FPC_POPADDRSTACK']; compilerproc;
  182. var
  183. hp : ^PExceptAddr;
  184. begin
  185. {$ifdef excdebug}
  186. writeln ('In Popaddrstack');
  187. {$endif}
  188. hp:=@ExceptAddrStack;
  189. If hp^=nil then
  190. begin
  191. {$ifdef excdebug}
  192. writeln ('At end of ExceptionAddresStack');
  193. {$endif}
  194. halt (255);
  195. end
  196. else
  197. begin
  198. hp^:=hp^^.Next;
  199. end;
  200. end;
  201. function fpc_PopObjectStack : TObject;[Public, Alias : 'FPC_POPOBJECTSTACK']; compilerproc;
  202. var
  203. hp,_ExceptObjectStack : PExceptObject;
  204. begin
  205. {$ifdef excdebug}
  206. writeln ('In PopObjectstack');
  207. {$endif}
  208. _ExceptObjectStack:=ExceptObjectStack;
  209. If _ExceptObjectStack=nil then
  210. begin
  211. {$ifdef excdebug}
  212. writeln ('At end of ExceptionObjectStack');
  213. {$endif}
  214. halt (1);
  215. end
  216. else
  217. begin
  218. { we need to return the exception object to dispose it }
  219. if _ExceptObjectStack^.refcount = 0 then begin
  220. fpc_PopObjectStack:=_ExceptObjectStack^.FObject;
  221. end else begin
  222. fpc_PopObjectStack:=nil;
  223. end;
  224. hp:=_ExceptObjectStack;
  225. ExceptObjectStack:=_ExceptObjectStack^.next;
  226. if assigned(hp^.frames) then
  227. freemem(hp^.frames);
  228. dispose(hp);
  229. erroraddr:=nil;
  230. end;
  231. end;
  232. function Internal_PopObjectStack: TObject; external name 'FPC_POPOBJECTSTACK';
  233. { this is for popping exception objects when a second exception is risen }
  234. { in an except/on }
  235. function fpc_PopSecondObjectStack : TObject;[Public, Alias : 'FPC_POPSECONDOBJECTSTACK']; compilerproc;
  236. var
  237. hp,_ExceptObjectStack : PExceptObject;
  238. begin
  239. {$ifdef excdebug}
  240. writeln ('In PopObjectstack');
  241. {$endif}
  242. _ExceptObjectStack:=ExceptObjectStack;
  243. If not(assigned(_ExceptObjectStack)) or
  244. not(assigned(_ExceptObjectStack^.next)) then
  245. begin
  246. {$ifdef excdebug}
  247. writeln ('At end of ExceptionObjectStack');
  248. {$endif}
  249. halt (1);
  250. end
  251. else
  252. begin
  253. if _ExceptObjectStack^.next^.refcount=0 then
  254. { we need to return the exception object to dispose it if refcount=0 }
  255. fpc_PopSecondObjectStack:=_ExceptObjectStack^.next^.FObject
  256. else
  257. fpc_PopSecondObjectStack:=nil;
  258. hp:=_ExceptObjectStack^.next;
  259. _ExceptObjectStack^.next:=hp^.next;
  260. if assigned(hp^.frames) then
  261. freemem(hp^.frames);
  262. dispose(hp);
  263. end;
  264. end;
  265. Procedure fpc_ReRaise;[Public, Alias : 'FPC_RERAISE']; compilerproc;
  266. var
  267. _ExceptAddrStack : PExceptAddr;
  268. begin
  269. {$ifdef excdebug}
  270. writeln ('In reraise');
  271. {$endif}
  272. _ExceptAddrStack:=ExceptAddrStack;
  273. If _ExceptAddrStack=Nil then
  274. DoUnHandledException;
  275. ExceptObjectStack^.refcount := 0;
  276. longjmp(_ExceptAddrStack^.Buf^,FPC_Exception);
  277. end;
  278. Function fpc_Catches(Objtype : TClass) : TObject;[Public, Alias : 'FPC_CATCHES']; compilerproc;
  279. var
  280. _Objtype : TExceptObjectClass;
  281. _ExceptObjectStack : PExceptObject;
  282. begin
  283. _ExceptObjectStack:=ExceptObjectStack;
  284. If _ExceptObjectStack=Nil then
  285. begin
  286. {$ifdef excdebug}
  287. Writeln ('Internal error.');
  288. {$endif}
  289. halt (255);
  290. end;
  291. _Objtype := TExceptObjectClass(Objtype);
  292. if Not ((_Objtype = TExceptObjectClass(CatchAllExceptions)) or
  293. (_ExceptObjectStack^.FObject is _ObjType)) then
  294. fpc_Catches:=Nil
  295. else
  296. begin
  297. // catch !
  298. fpc_Catches:=_ExceptObjectStack^.FObject;
  299. { this can't be done, because there could be a reraise (PFV)
  300. PopObjectStack;
  301. Also the PopAddrStack shouldn't be done, we do it now
  302. immediatly in the exception handler (FK)
  303. PopAddrStack; }
  304. end;
  305. end;
  306. Procedure fpc_DestroyException(o : TObject);[Public, Alias : 'FPC_DESTROYEXCEPTION']; compilerproc;
  307. begin
  308. { with free we're on the really safe side }
  309. o.Free;
  310. end;
  311. { TODO: no longer used, clean up }
  312. function fpc_GetExceptionAddr : Pointer;[Public, Alias : 'FPC_GETEXCEPTIONADDR']; compilerproc;
  313. var
  314. _ExceptObjectStack : PExceptObject;
  315. begin
  316. _ExceptObjectStack:=ExceptObjectStack;
  317. if _ExceptObjectStack=nil then
  318. fpc_GetExceptionAddr:=nil
  319. else
  320. fpc_GetExceptionAddr:=_ExceptObjectStack^.Addr;
  321. end;
  322. Procedure SysInitExceptions;
  323. {
  324. Initialize exceptionsupport
  325. }
  326. begin
  327. ExceptObjectstack:=Nil;
  328. ExceptAddrStack:=Nil;
  329. end;
  330. function fpc_safecallhandler(obj: TObject): HResult; [public,alias:'FPC_SAFECALLHANDLER']; compilerproc;
  331. var
  332. raiselist: PExceptObject;
  333. adr: Pointer;
  334. exc: TObject;
  335. begin
  336. raiselist:=ExceptObjectStack;
  337. if Assigned(raiseList) then
  338. adr:=raiseList^.Addr
  339. else
  340. adr:=nil;
  341. exc:=Internal_PopObjectStack;
  342. if Assigned(obj) then
  343. result:=obj.SafeCallException(exc,adr)
  344. else
  345. result:=E_UNEXPECTED;
  346. exc.Free;
  347. end;