except.inc 9.9 KB

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