except.inc 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  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. {$ifdef SUPPORT_THREADVAR}
  31. ThreadVar
  32. {$else SUPPORT_THREADVAR}
  33. Var
  34. {$endif SUPPORT_THREADVAR}
  35. ExceptAddrStack : PExceptAddr;
  36. ExceptObjectStack : PExceptObject;
  37. {$IFNDEF VIRTUALPASCAL}
  38. Function RaiseList : PExceptObject;
  39. begin
  40. RaiseList:=ExceptObjectStack;
  41. end;
  42. {$ENDIF}
  43. function AcquireExceptionObject: Pointer;
  44. begin
  45. If ExceptObjectStack=nil then begin
  46. AcquireExceptionObject := nil
  47. end else begin
  48. Inc(ExceptObjectStack^.refcount);
  49. AcquireExceptionObject := ExceptObjectStack^.FObject;
  50. end;
  51. end;
  52. procedure ReleaseExceptionObject;
  53. begin
  54. If ExceptObjectStack <> nil then begin
  55. if ExceptObjectStack^.refcount > 0 then begin
  56. Dec(ExceptObjectStack^.refcount);
  57. end;
  58. end;
  59. end;
  60. Function fpc_PushExceptAddr (Ft: Longint;_buf,_newaddr : pointer): PJmp_buf ;
  61. [Public, Alias : 'FPC_PUSHEXCEPTADDR'];{$ifndef NOSAVEREGISTERS}saveregisters;{$endif}compilerproc;
  62. var
  63. Buf : PJmp_buf;
  64. NewAddr : PExceptAddr;
  65. begin
  66. {$ifdef excdebug}
  67. writeln ('In PushExceptAddr');
  68. {$endif}
  69. If ExceptAddrstack=Nil then
  70. begin
  71. ExceptAddrStack:=PExceptAddr(_newaddr);
  72. ExceptAddrStack^.Next:=Nil;
  73. end
  74. else
  75. begin
  76. NewAddr:=PExceptAddr(_newaddr);
  77. NewAddr^.Next:=ExceptAddrStack;
  78. ExceptAddrStack:=NewAddr;
  79. end;
  80. buf:=PJmp_Buf(_buf);
  81. ExceptAddrStack^.Buf:=Buf;
  82. ExceptAddrStack^.FrameType:=ft;
  83. fpc_PushExceptAddr:=Buf;
  84. end;
  85. Procedure fpc_PushExceptObj (Obj : TObject; AnAddr,AFrame : Pointer);
  86. [Public, Alias : 'FPC_PUSHEXCEPTOBJECT'];{$ifndef NOSAVEREGISTERS}saveregisters;{$endif}compilerproc;
  87. var
  88. Newobj : PExceptObject;
  89. framebufsize,
  90. framecount : longint;
  91. frames : PPointer;
  92. prev_frame,
  93. curr_frame,
  94. caller_frame,
  95. caller_addr : Pointer;
  96. begin
  97. {$ifdef excdebug}
  98. writeln ('In PushExceptObject');
  99. {$endif}
  100. If ExceptObjectStack=Nil then
  101. begin
  102. New(ExceptObjectStack);
  103. ExceptObjectStack^.Next:=Nil;
  104. end
  105. else
  106. begin
  107. New(NewObj);
  108. NewObj^.Next:=ExceptObjectStack;
  109. ExceptObjectStack:=NewObj;
  110. end;
  111. ExceptObjectStack^.FObject:=Obj;
  112. ExceptObjectStack^.Addr:=AnAddr;
  113. ExceptObjectStack^.refcount:=0;
  114. { Backtrace }
  115. curr_frame:=AFrame;
  116. prev_frame:=get_frame;
  117. frames:=nil;
  118. framebufsize:=0;
  119. framecount:=0;
  120. while (framecount<RaiseMaxFrameCount) and (curr_frame > prev_frame) and
  121. (curr_frame<(StackBottom + StackLength)) do
  122. Begin
  123. caller_addr := get_caller_addr(curr_frame);
  124. caller_frame := get_caller_frame(curr_frame);
  125. if (caller_addr=nil) or
  126. (caller_frame=nil) then
  127. break;
  128. if (framecount>=framebufsize) then
  129. begin
  130. inc(framebufsize,16);
  131. reallocmem(frames,framebufsize*sizeof(pointer));
  132. end;
  133. frames[framecount]:=caller_addr;
  134. inc(framecount);
  135. prev_frame:=curr_frame;
  136. curr_frame:=caller_frame;
  137. End;
  138. ExceptObjectStack^.framecount:=framecount;
  139. ExceptObjectStack^.frames:=frames;
  140. end;
  141. { make it avalable for local use }
  142. Procedure fpc_PushExceptObj (Obj : TObject; AnAddr,AFrame : Pointer); [external name 'FPC_PUSHEXCEPTOBJECT'];
  143. Procedure DoUnHandledException;
  144. begin
  145. If (ExceptProc<>Nil) and (ExceptObjectStack<>Nil) then
  146. with ExceptObjectStack^ do
  147. TExceptProc(ExceptProc)(FObject,Addr,FrameCount,Frames);
  148. RunError(217);
  149. end;
  150. Function fpc_Raiseexception (Obj : TObject; AnAddr,AFrame : Pointer) : TObject;[Public, Alias : 'FPC_RAISEEXCEPTION']; compilerproc;
  151. begin
  152. {$ifdef excdebug}
  153. writeln ('In RaiseException');
  154. {$endif}
  155. fpc_Raiseexception:=nil;
  156. fpc_PushExceptObj(Obj,AnAddr,AFrame);
  157. If ExceptAddrStack=Nil then
  158. DoUnhandledException;
  159. if (RaiseProc <> nil) and (ExceptObjectStack <> nil) then
  160. with ExceptObjectStack^ do
  161. RaiseProc(FObject,Addr,FrameCount,Frames);
  162. longjmp(ExceptAddrStack^.Buf^,FPC_Exception);
  163. end;
  164. Procedure fpc_PopAddrStack;[Public, Alias : 'FPC_POPADDRSTACK']; compilerproc;
  165. begin
  166. {$ifdef excdebug}
  167. writeln ('In Popaddrstack');
  168. {$endif}
  169. If ExceptAddrStack=nil then
  170. begin
  171. writeln ('At end of ExceptionAddresStack');
  172. halt (255);
  173. end
  174. else
  175. begin
  176. ExceptAddrStack:=ExceptAddrStack^.Next;
  177. end;
  178. end;
  179. function fpc_PopObjectStack : TObject;[Public, Alias : 'FPC_POPOBJECTSTACK']; compilerproc;
  180. var
  181. hp : PExceptObject;
  182. begin
  183. {$ifdef excdebug}
  184. writeln ('In PopObjectstack');
  185. {$endif}
  186. If ExceptObjectStack=nil then
  187. begin
  188. writeln ('At end of ExceptionObjectStack');
  189. halt (1);
  190. end
  191. else
  192. begin
  193. { we need to return the exception object to dispose it }
  194. if ExceptObjectStack^.refcount = 0 then begin
  195. fpc_PopObjectStack:=ExceptObjectStack^.FObject;
  196. end else begin
  197. fpc_PopObjectStack:=nil;
  198. end;
  199. hp:=ExceptObjectStack;
  200. ExceptObjectStack:=ExceptObjectStack^.next;
  201. if assigned(hp^.frames) then
  202. freemem(hp^.frames);
  203. dispose(hp);
  204. end;
  205. end;
  206. { this is for popping exception objects when a second exception is risen }
  207. { in an except/on }
  208. function fpc_PopSecondObjectStack : TObject;[Public, Alias : 'FPC_POPSECONDOBJECTSTACK']; compilerproc;
  209. var
  210. hp : PExceptObject;
  211. begin
  212. {$ifdef excdebug}
  213. writeln ('In PopObjectstack');
  214. {$endif}
  215. If not(assigned(ExceptObjectStack)) or
  216. not(assigned(ExceptObjectStack^.next)) then
  217. begin
  218. writeln ('At end of ExceptionObjectStack');
  219. halt (1);
  220. end
  221. else
  222. begin
  223. if ExceptObjectStack^.next^.refcount=0 then
  224. { we need to return the exception object to dispose it if refcount=0 }
  225. fpc_PopSecondObjectStack:=ExceptObjectStack^.next^.FObject
  226. else
  227. fpc_PopSecondObjectStack:=nil;
  228. hp:=ExceptObjectStack^.next;
  229. ExceptObjectStack^.next:=hp^.next;
  230. if assigned(hp^.frames) then
  231. freemem(hp^.frames);
  232. dispose(hp);
  233. end;
  234. end;
  235. Procedure fpc_ReRaise;[Public, Alias : 'FPC_RERAISE']; compilerproc;
  236. begin
  237. {$ifdef excdebug}
  238. writeln ('In reraise');
  239. {$endif}
  240. If ExceptAddrStack=Nil then
  241. DoUnHandledException;
  242. ExceptObjectStack^.refcount := 0;
  243. longjmp(ExceptAddrStack^.Buf^,FPC_Exception);
  244. end;
  245. Function fpc_Catches(Objtype : TClass) : TObject;[Public, Alias : 'FPC_CATCHES']; compilerproc;
  246. var
  247. _Objtype : TExceptObjectClass;
  248. begin
  249. If ExceptObjectStack=Nil then
  250. begin
  251. Writeln ('Internal error.');
  252. halt (255);
  253. end;
  254. _Objtype := TExceptObjectClass(Objtype);
  255. if Not ((_Objtype = TExceptObjectClass(CatchAllExceptions)) or
  256. (ExceptObjectStack^.FObject is _ObjType)) then
  257. fpc_Catches:=Nil
  258. else
  259. begin
  260. // catch !
  261. fpc_Catches:=ExceptObjectStack^.FObject;
  262. { this can't be done, because there could be a reraise (PFV)
  263. PopObjectStack;
  264. Also the PopAddrStack shouldn't be done, we do it now
  265. immediatly in the exception handler (FK)
  266. PopAddrStack; }
  267. end;
  268. end;
  269. Procedure fpc_DestroyException(o : TObject);[Public, Alias : 'FPC_DESTROYEXCEPTION']; compilerproc;
  270. begin
  271. { with free we're on the really save side }
  272. o.Free;
  273. end;
  274. Procedure SysInitExceptions;
  275. {
  276. Initialize exceptionsupport
  277. }
  278. begin
  279. ExceptObjectstack:=Nil;
  280. ExceptAddrStack:=Nil;
  281. end;