except.inc 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  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. {$ifdef FPC_HAS_FEATURE_THREADING}
  15. ThreadVar
  16. {$else FPC_HAS_FEATURE_THREADING}
  17. Var
  18. {$endif FPC_HAS_FEATURE_THREADING}
  19. ExceptAddrStack : PExceptAddr;
  20. ExceptObjectStack : PExceptObject;
  21. ExceptTryLevel : ObjpasInt;
  22. {$ifdef FPC_USE_PSABIEH}
  23. {$i psabieh.inc}
  24. {$endif}
  25. Function RaiseList : PExceptObject;
  26. begin
  27. RaiseList:=ExceptObjectStack;
  28. end;
  29. function AcquireExceptionObject: Pointer;
  30. var
  31. _ExceptObjectStack : PExceptObject;
  32. begin
  33. _ExceptObjectStack:=ExceptObjectStack;
  34. If _ExceptObjectStack<>nil then
  35. begin
  36. Inc(_ExceptObjectStack^.refcount);
  37. AcquireExceptionObject := _ExceptObjectStack^.FObject;
  38. end
  39. else
  40. RunError(231);
  41. end;
  42. procedure ReleaseExceptionObject;
  43. var
  44. _ExceptObjectStack : PExceptObject;
  45. begin
  46. _ExceptObjectStack:=ExceptObjectStack;
  47. If _ExceptObjectStack <> nil then
  48. begin
  49. if _ExceptObjectStack^.refcount > 0 then
  50. Dec(_ExceptObjectStack^.refcount);
  51. end
  52. else
  53. RunError(231);
  54. end;
  55. Function fpc_PushExceptAddr (Ft: {$ifdef CPU16}SmallInt{$else}Longint{$endif};_buf,_newaddr : pointer): PJmp_buf ;
  56. [Public, Alias : 'FPC_PUSHEXCEPTADDR'];compilerproc;
  57. var
  58. _ExceptAddrstack : ^PExceptAddr;
  59. begin
  60. {$ifdef excdebug}
  61. writeln ('In PushExceptAddr');
  62. {$endif}
  63. _ExceptAddrstack:=@ExceptAddrstack;
  64. PExceptAddr(_newaddr)^.Next:=_ExceptAddrstack^;
  65. _ExceptAddrStack^:=PExceptAddr(_newaddr);
  66. PExceptAddr(_newaddr)^.Buf:=PJmp_Buf(_buf);
  67. PExceptAddr(_newaddr)^.FrameType:=ft;
  68. result:=PJmp_Buf(_buf);
  69. end;
  70. { This routine is called only from fpc_raiseexception, which uses ExceptTryLevel
  71. flag to guard against repeated exceptions which can occur due to corrupted stack
  72. or heap. }
  73. function PushExceptObject(Obj : TObject; AnAddr : CodePointer; AFrame : Pointer): PExceptObject;
  74. var
  75. Newobj : PExceptObject;
  76. _ExceptObjectStack : ^PExceptObject;
  77. framebufsize,
  78. framecount : longint;
  79. frames : PCodePointer;
  80. prev_frame,
  81. curr_frame : Pointer;
  82. curr_addr : CodePointer;
  83. begin
  84. {$ifdef excdebug}
  85. writeln ('In PushExceptObject');
  86. {$endif}
  87. _ExceptObjectStack:=@ExceptObjectStack;
  88. New(NewObj);
  89. NewObj^.Next:=_ExceptObjectStack^;
  90. _ExceptObjectStack^:=NewObj;
  91. NewObj^.FObject:=Obj;
  92. NewObj^.Addr:=AnAddr;
  93. NewObj^.refcount:=0;
  94. { Backtrace }
  95. curr_frame:=AFrame;
  96. curr_addr:=AnAddr;
  97. frames:=nil;
  98. framebufsize:=0;
  99. framecount:=0;
  100. { The frame pointer of this procedure is used as initial stack bottom value. }
  101. prev_frame:=get_frame;
  102. while (framecount<RaiseMaxFrameCount) and (curr_frame > prev_frame) and
  103. (curr_frame<StackTop) do
  104. Begin
  105. prev_frame:=curr_frame;
  106. get_caller_stackinfo(curr_frame,curr_addr);
  107. if (curr_addr=nil) or
  108. (curr_frame=nil) then
  109. break;
  110. if (framecount>=framebufsize) then
  111. begin
  112. inc(framebufsize,16);
  113. reallocmem(frames,framebufsize*sizeof(codepointer));
  114. end;
  115. frames[framecount]:=curr_addr;
  116. inc(framecount);
  117. End;
  118. NewObj^.framecount:=framecount;
  119. NewObj^.frames:=frames;
  120. Result:=NewObj;
  121. end;
  122. Procedure DoUnHandledException;
  123. var
  124. _ExceptObjectStack : PExceptObject;
  125. begin
  126. _ExceptObjectStack:=ExceptObjectStack;
  127. If (ExceptProc<>Nil) and (_ExceptObjectStack<>Nil) then
  128. with _ExceptObjectStack^ do
  129. begin
  130. TExceptProc(ExceptProc)(FObject,Addr,FrameCount,Frames);
  131. halt(217)
  132. end;
  133. if erroraddr = nil then
  134. RunError(217)
  135. else
  136. Halt(errorcode);
  137. end;
  138. {$ifndef FPC_SYSTEM_HAS_RAISEEXCEPTION}
  139. procedure fpc_RaiseException (Obj : TObject; AnAddr : CodePointer; AFrame : Pointer);[Public, Alias : 'FPC_RAISEEXCEPTION']; compilerproc;
  140. var
  141. _ExceptObjectStack : PExceptObject;
  142. _ExceptAddrstack : PExceptAddr;
  143. begin
  144. {$ifdef excdebug}
  145. writeln ('In RaiseException');
  146. {$endif}
  147. if ExceptTryLevel<>0 then
  148. Halt(217);
  149. ExceptTryLevel:=1;
  150. PushExceptObject(Obj,AnAddr,AFrame);
  151. { if PushExceptObject causes another exception, the following won't be executed,
  152. causing halt upon entering this routine recursively. }
  153. ExceptTryLevel:=0;
  154. _ExceptAddrstack:=ExceptAddrStack;
  155. If _ExceptAddrStack=Nil then
  156. DoUnhandledException;
  157. _ExceptObjectStack:=ExceptObjectStack;
  158. if (RaiseProc <> nil) and (_ExceptObjectStack <> nil) then
  159. with _ExceptObjectStack^ do
  160. RaiseProc(FObject,Addr,FrameCount,Frames);
  161. longjmp(_ExceptAddrStack^.Buf^,FPC_Exception);
  162. end;
  163. {$endif FPC_SYSTEM_HAS_RAISEEXCEPTION}
  164. Procedure fpc_PopAddrStack;[Public, Alias : 'FPC_POPADDRSTACK']; compilerproc;
  165. var
  166. hp : ^PExceptAddr;
  167. begin
  168. {$ifdef excdebug}
  169. writeln ('In Popaddrstack');
  170. {$endif}
  171. hp:=@ExceptAddrStack;
  172. If hp^=nil then
  173. begin
  174. {$ifdef excdebug}
  175. writeln ('At end of ExceptionAddresStack');
  176. {$endif}
  177. halt (255);
  178. end
  179. else
  180. begin
  181. hp^:=hp^^.Next;
  182. end;
  183. end;
  184. function fpc_PopObjectStack : TObject;[Public, Alias : 'FPC_POPOBJECTSTACK']; compilerproc;
  185. var
  186. hp : PExceptObject;
  187. begin
  188. {$ifdef excdebug}
  189. writeln ('In PopObjectstack');
  190. {$endif}
  191. hp:=ExceptObjectStack;
  192. if hp=nil then
  193. begin
  194. {$ifdef excdebug}
  195. writeln ('At end of ExceptionObjectStack');
  196. {$endif}
  197. halt (1);
  198. end
  199. else
  200. begin
  201. { we need to return the exception object to dispose it }
  202. if hp^.refcount = 0 then
  203. fpc_PopObjectStack:=hp^.FObject
  204. else
  205. fpc_PopObjectStack:=nil;
  206. ExceptObjectStack:=hp^.next;
  207. if assigned(hp^.frames) then
  208. freemem(hp^.frames);
  209. dispose(hp);
  210. erroraddr:=nil;
  211. end;
  212. end;
  213. { this is for popping exception objects when a second exception is risen }
  214. { in an except/on }
  215. function fpc_PopSecondObjectStack : TObject;[Public, Alias : 'FPC_POPSECONDOBJECTSTACK']; compilerproc;
  216. var
  217. hp,_ExceptObjectStack : PExceptObject;
  218. begin
  219. {$ifdef excdebug}
  220. writeln ('In PopObjectstack');
  221. {$endif}
  222. _ExceptObjectStack:=ExceptObjectStack;
  223. If not(assigned(_ExceptObjectStack)) or
  224. not(assigned(_ExceptObjectStack^.next)) then
  225. begin
  226. {$ifdef excdebug}
  227. writeln ('At end of ExceptionObjectStack');
  228. {$endif}
  229. halt (1);
  230. end
  231. else
  232. begin
  233. if _ExceptObjectStack^.next^.refcount=0 then
  234. { we need to return the exception object to dispose it if refcount=0 }
  235. fpc_PopSecondObjectStack:=_ExceptObjectStack^.next^.FObject
  236. else
  237. fpc_PopSecondObjectStack:=nil;
  238. hp:=_ExceptObjectStack^.next;
  239. _ExceptObjectStack^.next:=hp^.next;
  240. if assigned(hp^.frames) then
  241. freemem(hp^.frames);
  242. dispose(hp);
  243. end;
  244. end;
  245. {$ifndef FPC_SYSTEM_HAS_RERAISE}
  246. Procedure fpc_ReRaise;[Public, Alias : 'FPC_RERAISE']; compilerproc;
  247. var
  248. _ExceptAddrStack : PExceptAddr;
  249. begin
  250. {$ifdef excdebug}
  251. writeln ('In reraise');
  252. {$endif}
  253. _ExceptAddrStack:=ExceptAddrStack;
  254. If _ExceptAddrStack=Nil then
  255. DoUnHandledException;
  256. ExceptObjectStack^.refcount := 0;
  257. longjmp(_ExceptAddrStack^.Buf^,FPC_Exception);
  258. end;
  259. {$endif FPC_SYSTEM_HAS_RERAISE}
  260. function Internal_PopSecondObjectStack : TObject; external name 'FPC_POPSECONDOBJECTSTACK';
  261. function Internal_PopObjectStack: TObject; external name 'FPC_POPOBJECTSTACK';
  262. procedure Internal_Reraise; external name 'FPC_RERAISE';
  263. Function fpc_Catches(Objtype : TClass) : TObject;[Public, Alias : 'FPC_CATCHES']; compilerproc;
  264. var
  265. _ExceptObjectStack : PExceptObject;
  266. begin
  267. _ExceptObjectStack:=ExceptObjectStack;
  268. If _ExceptObjectStack=Nil then
  269. begin
  270. {$ifdef excdebug}
  271. Writeln ('Internal error.');
  272. {$endif}
  273. halt (255);
  274. end;
  275. if Not ((Objtype = TClass(CatchAllExceptions)) or
  276. (_ExceptObjectStack^.FObject is ObjType)) then
  277. fpc_Catches:=Nil
  278. else
  279. begin
  280. // catch !
  281. fpc_Catches:=_ExceptObjectStack^.FObject;
  282. { this can't be done, because there could be a reraise (PFV)
  283. PopObjectStack;
  284. Also the PopAddrStack shouldn't be done, we do it now
  285. immediatly in the exception handler (FK)
  286. PopAddrStack; }
  287. end;
  288. end;
  289. Procedure SysInitExceptions;
  290. {
  291. Initialize exceptionsupport
  292. }
  293. begin
  294. ExceptObjectstack:=Nil;
  295. ExceptAddrStack:=Nil;
  296. end;
  297. {$ifndef FPC_SYSTEM_HAS_DONEEXCEPTION}
  298. procedure fpc_doneexception;[public,alias:'FPC_DONEEXCEPTION'] compilerproc;
  299. begin
  300. Internal_PopObjectStack.Free;
  301. end;
  302. {$endif FPC_SYSTEM_HAS_DONEEXCEPTION}
  303. {$ifndef FPC_SYSTEM_HAS_RAISENESTED}
  304. procedure fpc_raise_nested;[public,alias:'FPC_RAISE_NESTED']compilerproc;
  305. begin
  306. Internal_PopSecondObjectStack.Free;
  307. Internal_Reraise;
  308. end;
  309. {$endif FPC_SYSTEM_HAS_RAISENESTED}
  310. {$ifndef FPC_SYSTEM_HAS_SAFECALLHANDLER}
  311. function fpc_safecallhandler(obj: TObject): HResult; [public,alias:'FPC_SAFECALLHANDLER']; compilerproc;
  312. var
  313. raiselist: PExceptObject;
  314. adr: CodePointer;
  315. exc: TObject;
  316. begin
  317. raiselist:=ExceptObjectStack;
  318. if Assigned(raiseList) then
  319. adr:=raiseList^.Addr
  320. else
  321. adr:=nil;
  322. exc:=Internal_PopObjectStack;
  323. if Assigned(obj) and Assigned(exc) then
  324. result:=obj.SafeCallException(exc,adr)
  325. else
  326. result:=E_UNEXPECTED;
  327. exc.Free;
  328. end;
  329. {$endif FPC_SYSTEM_HAS_SAFECALLHANDLER}