except.inc 7.9 KB

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