except.inc 7.9 KB

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