except.inc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  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. { we need to return the exception object to dispose it }
  257. fpc_PopSecondObjectStack:=ExceptObjectStack^.next^.FObject;
  258. hp:=ExceptObjectStack^.next;
  259. ExceptObjectStack^.next:=hp^.next;
  260. if assigned(hp^.frames) then
  261. freemem(hp^.frames);
  262. dispose(hp);
  263. end;
  264. end;
  265. Procedure fpc_ReRaise;[Public, Alias : 'FPC_RERAISE']; {$ifdef hascompilerproc} compilerproc; {$endif}
  266. begin
  267. {$ifdef excdebug}
  268. writeln ('In reraise');
  269. {$endif}
  270. If ExceptAddrStack=Nil then
  271. DoUnHandledException;
  272. ExceptObjectStack^.refcount := 0;
  273. longjmp(ExceptAddrStack^.Buf^,FPC_Exception);
  274. end;
  275. Function fpc_Catches(Objtype : TClass) : TObject;[Public, Alias : 'FPC_CATCHES']; {$ifdef hascompilerproc} compilerproc; {$endif}
  276. var
  277. _Objtype : TExceptObjectClass;
  278. begin
  279. If ExceptObjectStack=Nil then
  280. begin
  281. Writeln ('Internal error.');
  282. halt (255);
  283. end;
  284. _Objtype := TExceptObjectClass(Objtype);
  285. if Not ((_Objtype = TExceptObjectClass(CatchAllExceptions)) or
  286. (ExceptObjectStack^.FObject is _ObjType)) then
  287. fpc_Catches:=Nil
  288. else
  289. begin
  290. // catch !
  291. fpc_Catches:=ExceptObjectStack^.FObject;
  292. { this can't be done, because there could be a reraise (PFV)
  293. PopObjectStack;
  294. Also the PopAddrStack shouldn't be done, we do it now
  295. immediatly in the exception handler (FK)
  296. PopAddrStack; }
  297. end;
  298. end;
  299. Procedure fpc_DestroyException(o : TObject);[Public, Alias : 'FPC_DESTROYEXCEPTION']; {$ifdef hascompilerproc} compilerproc; {$endif}
  300. begin
  301. { with free we're on the really save side }
  302. o.Free;
  303. end;
  304. Procedure SysInitExceptions;
  305. {
  306. Initialize exceptionsupport
  307. }
  308. begin
  309. ExceptObjectstack:=Nil;
  310. ExceptAddrStack:=Nil;
  311. end;
  312. {
  313. $Log$
  314. Revision 1.18 2005-01-29 17:01:18 peter
  315. * fix crash with backtrace if invalid frame is passed
  316. Revision 1.17 2005/01/26 17:07:10 peter
  317. * retrieve backtrace when exception is raised
  318. * RaiseMaxFrameCount added to limit the number of backtraces, setting
  319. it to 0 disables backtraces. Default is 16
  320. Revision 1.16 2004/10/24 20:01:41 peter
  321. * saveregisters calling convention is obsolete
  322. Revision 1.15 2004/04/27 18:47:51 florian
  323. * exception addr record size for 64 bit systems fixed
  324. Revision 1.14 2004/02/05 01:16:12 florian
  325. + completed x86-64/linux system unit
  326. Revision 1.13 2003/11/26 20:12:08 michael
  327. + New runerror 231 (exception stack error) and 232 (nothread support)
  328. Revision 1.12 2003/10/06 15:59:20 florian
  329. + applied patch for ref. counted exceptions by Johannes Berg
  330. Revision 1.11 2003/09/06 21:56:29 marco
  331. * one VIRTUALPASCAL
  332. Revision 1.10 2003/05/01 08:05:23 florian
  333. * started to make the rtl 64 bit save by introducing SizeInt and SizeUInt (similar to size_t of C)
  334. Revision 1.9 2002/10/14 19:39:17 peter
  335. * threads unit added for thread support
  336. Revision 1.8 2002/09/07 15:07:45 peter
  337. * old logs removed and tabs fixed
  338. }