except.inc 8.0 KB

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