except.inc 9.6 KB

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