except.inc 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 by Michael Van Canneyt
  5. member of the Free Pascal development team
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. {****************************************************************************
  13. Exception support
  14. ****************************************************************************}
  15. Const
  16. { Type of exception. Currently only one. }
  17. FPC_EXCEPTION = 1;
  18. { types of frames for the exception address stack }
  19. cExceptionFrame = 1;
  20. cFinalizeFrame = 2;
  21. Type
  22. PExceptAddr = ^TExceptAddr;
  23. TExceptAddr = record
  24. buf : pjmp_buf;
  25. next : PExceptAddr;
  26. frametype : Longint;
  27. end;
  28. TExceptObjectClass = Class of TObject;
  29. Const
  30. CatchAllExceptions : PtrInt = -1;
  31. {$ifdef SUPPORT_THREADVAR}
  32. ThreadVar
  33. {$else SUPPORT_THREADVAR}
  34. Var
  35. {$endif SUPPORT_THREADVAR}
  36. ExceptAddrStack : PExceptAddr;
  37. ExceptObjectStack : PExceptObject;
  38. {$IFNDEF VIRTUALPASCAL}
  39. Function RaiseList : PExceptObject;
  40. begin
  41. RaiseList:=ExceptObjectStack;
  42. end;
  43. {$ENDIF}
  44. function AcquireExceptionObject: Pointer;
  45. begin
  46. If ExceptObjectStack=nil then begin
  47. runerror(231); // which error?
  48. end else begin
  49. Inc(ExceptObjectStack^.refcount);
  50. AcquireExceptionObject := ExceptObjectStack^.FObject;
  51. end;
  52. end;
  53. procedure ReleaseExceptionObject;
  54. begin
  55. If ExceptObjectStack=nil then begin
  56. runerror(231); // which error?
  57. end else begin
  58. if ExceptObjectStack^.refcount = 0 then begin
  59. runerror(231); // which error?
  60. end;
  61. Dec(ExceptObjectStack^.refcount);
  62. end;
  63. end;
  64. {$ifndef HAS_ADDR_STACK_ON_STACK}
  65. Function fpc_PushExceptAddr (Ft: Longint): PJmp_buf ;
  66. [Public, Alias : 'FPC_PUSHEXCEPTADDR'];{$ifndef NOSAVEREGISTERS}saveregisters;{$endif}
  67. {$else HAS_ADDR_STACK_ON_STACK}
  68. Function fpc_PushExceptAddr (Ft: Longint;_buf,_newaddr : pointer): PJmp_buf ;
  69. [Public, Alias : 'FPC_PUSHEXCEPTADDR'];{$ifndef NOSAVEREGISTERS}saveregisters;{$endif}{$ifdef hascompilerproc} compilerproc; {$endif}
  70. {$endif HAS_ADDR_STACK_ON_STACK}
  71. var
  72. Buf : PJmp_buf;
  73. NewAddr : PExceptAddr;
  74. begin
  75. {$ifdef excdebug}
  76. writeln ('In PushExceptAddr');
  77. {$endif}
  78. If ExceptAddrstack=Nil then
  79. begin
  80. {$ifndef HAS_ADDR_STACK_ON_STACK}
  81. New(ExceptAddrStack);
  82. {$else HAS_ADDR_STACK_ON_STACK}
  83. ExceptAddrStack:=PExceptAddr(_newaddr);
  84. {$endif HAS_ADDR_STACK_ON_STACK}
  85. ExceptAddrStack^.Next:=Nil;
  86. end
  87. else
  88. begin
  89. {$ifndef HAS_ADDR_STACK_ON_STACK}
  90. New(NewAddr);
  91. {$else HAS_ADDR_STACK_ON_STACK}
  92. NewAddr:=PExceptAddr(_newaddr);
  93. {$endif HAS_ADDR_STACK_ON_STACK}
  94. NewAddr^.Next:=ExceptAddrStack;
  95. ExceptAddrStack:=NewAddr;
  96. end;
  97. {$ifndef HAS_ADDR_STACK_ON_STACK}
  98. new(buf);
  99. {$else HAS_ADDR_STACK_ON_STACK}
  100. buf:=PJmp_Buf(_buf);
  101. {$endif HAS_ADDR_STACK_ON_STACK}
  102. ExceptAddrStack^.Buf:=Buf;
  103. ExceptAddrStack^.FrameType:=ft;
  104. fpc_PushExceptAddr:=Buf;
  105. end;
  106. Procedure fpc_PushExceptObj (Obj : TObject; AnAddr,AFrame : Pointer);
  107. [Public, Alias : 'FPC_PUSHEXCEPTOBJECT'];{$ifndef NOSAVEREGISTERS}saveregisters;{$endif}{$ifdef hascompilerproc} compilerproc; {$endif}
  108. var
  109. Newobj : PExceptObject;
  110. framebufsize,
  111. framecount : longint;
  112. frames : PPointer;
  113. prev_frame,
  114. curr_frame,
  115. caller_frame,
  116. caller_addr : Pointer;
  117. begin
  118. {$ifdef excdebug}
  119. writeln ('In PushExceptObject');
  120. {$endif}
  121. If ExceptObjectStack=Nil then
  122. begin
  123. New(ExceptObjectStack);
  124. ExceptObjectStack^.Next:=Nil;
  125. end
  126. else
  127. begin
  128. New(NewObj);
  129. NewObj^.Next:=ExceptObjectStack;
  130. ExceptObjectStack:=NewObj;
  131. end;
  132. ExceptObjectStack^.FObject:=Obj;
  133. ExceptObjectStack^.Addr:=AnAddr;
  134. ExceptObjectStack^.refcount:=0;
  135. { Backtrace }
  136. curr_frame:=AFrame;
  137. prev_frame:=get_frame;
  138. frames:=nil;
  139. framebufsize:=0;
  140. framecount:=0;
  141. while (framecount<RaiseMaxFrameCount) and (curr_frame > prev_frame) Do
  142. Begin
  143. caller_addr := get_caller_addr(curr_frame);
  144. caller_frame := get_caller_frame(curr_frame);
  145. if (caller_addr=nil) or
  146. (caller_frame=nil) then
  147. break;
  148. if (framecount>=framebufsize) then
  149. begin
  150. inc(framebufsize,16);
  151. reallocmem(frames,framebufsize*sizeof(pointer));
  152. end;
  153. frames[framecount]:=caller_addr;
  154. inc(framecount);
  155. prev_frame:=curr_frame;
  156. curr_frame:=caller_frame;
  157. End;
  158. ExceptObjectStack^.framecount:=framecount;
  159. ExceptObjectStack^.frames:=frames;
  160. end;
  161. {$ifdef hascompilerproc}
  162. { make it avalable for local use }
  163. Procedure fpc_PushExceptObj (Obj : TObject; AnAddr,AFrame : Pointer); [external name 'FPC_PUSHEXCEPTOBJECT'];
  164. {$endif}
  165. Procedure DoUnHandledException;
  166. begin
  167. If (ExceptProc<>Nil) and (ExceptObjectStack<>Nil) then
  168. with ExceptObjectStack^ do
  169. TExceptProc(ExceptProc)(FObject,Addr,FrameCount,Frames);
  170. RunError(217);
  171. end;
  172. Function fpc_Raiseexception (Obj : TObject; AnAddr,AFrame : Pointer) : TObject;[Public, Alias : 'FPC_RAISEEXCEPTION']; {$ifdef hascompilerproc} compilerproc; {$endif}
  173. begin
  174. {$ifdef excdebug}
  175. writeln ('In RaiseException');
  176. {$endif}
  177. fpc_Raiseexception:=nil;
  178. fpc_PushExceptObj(Obj,AnAddr,AFrame);
  179. If ExceptAddrStack=Nil then
  180. DoUnhandledException;
  181. if (RaiseProc <> nil) and (ExceptObjectStack <> nil) then
  182. with ExceptObjectStack^ do
  183. RaiseProc(FObject,Addr,FrameCount,Frames);
  184. longjmp(ExceptAddrStack^.Buf^,FPC_Exception);
  185. end;
  186. Procedure fpc_PopAddrStack;[Public, Alias : 'FPC_POPADDRSTACK']; {$ifdef hascompilerproc} compilerproc; {$endif}
  187. {$ifndef HAS_ADDR_STACK_ON_STACK}
  188. var
  189. hp : PExceptAddr;
  190. {$endif HAS_ADDR_STACK_ON_STACK}
  191. begin
  192. {$ifdef excdebug}
  193. writeln ('In Popaddrstack');
  194. {$endif}
  195. If ExceptAddrStack=nil then
  196. begin
  197. writeln ('At end of ExceptionAddresStack');
  198. halt (255);
  199. end
  200. else
  201. begin
  202. {$ifndef HAS_ADDR_STACK_ON_STACK}
  203. hp:=ExceptAddrStack;
  204. ExceptAddrStack:=ExceptAddrStack^.Next;
  205. dispose(hp^.buf);
  206. dispose(hp);
  207. {$else HAS_ADDR_STACK_ON_STACK}
  208. ExceptAddrStack:=ExceptAddrStack^.Next;
  209. {$endif HAS_ADDR_STACK_ON_STACK}
  210. end;
  211. end;
  212. function fpc_PopObjectStack : TObject;[Public, Alias : 'FPC_POPOBJECTSTACK']; {$ifdef hascompilerproc} compilerproc; {$endif}
  213. var
  214. hp : PExceptObject;
  215. begin
  216. {$ifdef excdebug}
  217. writeln ('In PopObjectstack');
  218. {$endif}
  219. If ExceptObjectStack=nil then
  220. begin
  221. writeln ('At end of ExceptionObjectStack');
  222. halt (1);
  223. end
  224. else
  225. begin
  226. { we need to return the exception object to dispose it }
  227. if ExceptObjectStack^.refcount = 0 then begin
  228. fpc_PopObjectStack:=ExceptObjectStack^.FObject;
  229. end else begin
  230. fpc_PopObjectStack:=nil;
  231. end;
  232. hp:=ExceptObjectStack;
  233. ExceptObjectStack:=ExceptObjectStack^.next;
  234. if assigned(hp^.frames) then
  235. freemem(hp^.frames);
  236. dispose(hp);
  237. end;
  238. end;
  239. { this is for popping exception objects when a second exception is risen }
  240. { in an except/on }
  241. function fpc_PopSecondObjectStack : TObject;[Public, Alias : 'FPC_POPSECONDOBJECTSTACK']; {$ifdef hascompilerproc} compilerproc; {$endif}
  242. var
  243. hp : PExceptObject;
  244. begin
  245. {$ifdef excdebug}
  246. writeln ('In PopObjectstack');
  247. {$endif}
  248. If not(assigned(ExceptObjectStack)) or
  249. not(assigned(ExceptObjectStack^.next)) then
  250. begin
  251. writeln ('At end of ExceptionObjectStack');
  252. halt (1);
  253. end
  254. else
  255. begin
  256. if ExceptObjectStack^.next^.refcount=0 then
  257. { we need to return the exception object to dispose it if refcount=0 }
  258. fpc_PopSecondObjectStack:=ExceptObjectStack^.next^.FObject
  259. else
  260. fpc_PopSecondObjectStack:=nil;
  261. hp:=ExceptObjectStack^.next;
  262. ExceptObjectStack^.next:=hp^.next;
  263. if assigned(hp^.frames) then
  264. freemem(hp^.frames);
  265. dispose(hp);
  266. end;
  267. end;
  268. Procedure fpc_ReRaise;[Public, Alias : 'FPC_RERAISE']; {$ifdef hascompilerproc} compilerproc; {$endif}
  269. begin
  270. {$ifdef excdebug}
  271. writeln ('In reraise');
  272. {$endif}
  273. If ExceptAddrStack=Nil then
  274. DoUnHandledException;
  275. ExceptObjectStack^.refcount := 0;
  276. longjmp(ExceptAddrStack^.Buf^,FPC_Exception);
  277. end;
  278. Function fpc_Catches(Objtype : TClass) : TObject;[Public, Alias : 'FPC_CATCHES']; {$ifdef hascompilerproc} compilerproc; {$endif}
  279. var
  280. _Objtype : TExceptObjectClass;
  281. begin
  282. If ExceptObjectStack=Nil then
  283. begin
  284. Writeln ('Internal error.');
  285. halt (255);
  286. end;
  287. _Objtype := TExceptObjectClass(Objtype);
  288. if Not ((_Objtype = TExceptObjectClass(CatchAllExceptions)) or
  289. (ExceptObjectStack^.FObject is _ObjType)) then
  290. fpc_Catches:=Nil
  291. else
  292. begin
  293. // catch !
  294. fpc_Catches:=ExceptObjectStack^.FObject;
  295. { this can't be done, because there could be a reraise (PFV)
  296. PopObjectStack;
  297. Also the PopAddrStack shouldn't be done, we do it now
  298. immediatly in the exception handler (FK)
  299. PopAddrStack; }
  300. end;
  301. end;
  302. Procedure fpc_DestroyException(o : TObject);[Public, Alias : 'FPC_DESTROYEXCEPTION']; {$ifdef hascompilerproc} compilerproc; {$endif}
  303. begin
  304. { with free we're on the really save side }
  305. o.Free;
  306. end;
  307. Procedure SysInitExceptions;
  308. {
  309. Initialize exceptionsupport
  310. }
  311. begin
  312. ExceptObjectstack:=Nil;
  313. ExceptAddrStack:=Nil;
  314. end;
  315. {
  316. $Log$
  317. Revision 1.20 2005-04-03 11:32:05 florian
  318. * ref. counting for popping second exceptiono object fixed
  319. Revision 1.19 2005/02/14 17:13:22 peter
  320. * truncate log
  321. Revision 1.18 2005/01/29 17:01:18 peter
  322. * fix crash with backtrace if invalid frame is passed
  323. Revision 1.17 2005/01/26 17:07:10 peter
  324. * retrieve backtrace when exception is raised
  325. * RaiseMaxFrameCount added to limit the number of backtraces, setting
  326. it to 0 disables backtraces. Default is 16
  327. }