except.inc 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  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 : PtrInt;
  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. NewObj:=AllocMem(sizeof(TExceptObject));
  89. NewObj^.Next:=_ExceptObjectStack^;
  90. _ExceptObjectStack^:=NewObj;
  91. NewObj^.FObject:=Obj;
  92. NewObj^.Addr:=AnAddr;
  93. if assigned(get_frame) then
  94. begin
  95. NewObj^.refcount:=0;
  96. { Backtrace }
  97. curr_frame:=AFrame;
  98. curr_addr:=AnAddr;
  99. frames:=nil;
  100. framecount:=0;
  101. framebufsize:=0;
  102. { The frame pointer of this procedure is used as initial stack bottom value. }
  103. prev_frame:=get_frame;
  104. while (framecount<RaiseMaxFrameCount) and (curr_frame > prev_frame) and
  105. (curr_frame<StackTop) do
  106. Begin
  107. prev_frame:=curr_frame;
  108. get_caller_stackinfo(curr_frame,curr_addr);
  109. if (curr_addr=nil) or
  110. (curr_frame=nil) then
  111. break;
  112. if (framecount>=framebufsize) then
  113. begin
  114. inc(framebufsize,16);
  115. reallocmem(frames,framebufsize*sizeof(codepointer));
  116. end;
  117. frames[framecount]:=curr_addr;
  118. inc(framecount);
  119. End;
  120. NewObj^.framecount:=framecount;
  121. NewObj^.frames:=frames;
  122. end;
  123. Result:=NewObj;
  124. end;
  125. Procedure DoUnHandledException;
  126. var
  127. _ExceptObjectStack : PExceptObject;
  128. begin
  129. _ExceptObjectStack:=ExceptObjectStack;
  130. If (ExceptProc<>Nil) and (_ExceptObjectStack<>Nil) then
  131. with _ExceptObjectStack^ do
  132. begin
  133. TExceptProc(ExceptProc)(FObject,Addr,FrameCount,Frames);
  134. halt(217)
  135. end;
  136. if erroraddr = nil then
  137. RunError(217)
  138. else
  139. Halt(errorcode);
  140. end;
  141. {$ifndef FPC_SYSTEM_HAS_RAISEEXCEPTION}
  142. procedure fpc_RaiseException (Obj : TObject; AnAddr : CodePointer; AFrame : Pointer);[Public, Alias : 'FPC_RAISEEXCEPTION']; compilerproc;
  143. var
  144. _ExceptObjectStack : PExceptObject;
  145. _ExceptAddrstack : PExceptAddr;
  146. begin
  147. {$ifdef excdebug}
  148. writeln ('In RaiseException');
  149. {$endif}
  150. if ExceptTryLevel<>0 then
  151. Halt(217);
  152. ExceptTryLevel:=1;
  153. PushExceptObject(Obj,AnAddr,AFrame);
  154. { if PushExceptObject causes another exception, the following won't be executed,
  155. causing halt upon entering this routine recursively. }
  156. ExceptTryLevel:=0;
  157. _ExceptAddrstack:=ExceptAddrStack;
  158. If _ExceptAddrStack=Nil then
  159. DoUnhandledException;
  160. _ExceptObjectStack:=ExceptObjectStack;
  161. if (RaiseProc <> nil) and (_ExceptObjectStack <> nil) then
  162. with _ExceptObjectStack^ do
  163. RaiseProc(FObject,Addr,FrameCount,Frames);
  164. longjmp(_ExceptAddrStack^.Buf^,FPC_Exception);
  165. end;
  166. {$endif FPC_SYSTEM_HAS_RAISEEXCEPTION}
  167. Procedure fpc_PopAddrStack;[Public, Alias : 'FPC_POPADDRSTACK']; compilerproc;
  168. var
  169. hp : ^PExceptAddr;
  170. begin
  171. {$ifdef excdebug}
  172. writeln ('In Popaddrstack');
  173. {$endif}
  174. hp:=@ExceptAddrStack;
  175. If hp^=nil then
  176. begin
  177. {$ifdef excdebug}
  178. writeln ('At end of ExceptionAddresStack');
  179. {$endif}
  180. halt (255);
  181. end
  182. else
  183. begin
  184. hp^:=hp^^.Next;
  185. end;
  186. end;
  187. function fpc_PopObjectStack : TObject;[Public, Alias : 'FPC_POPOBJECTSTACK']; compilerproc;
  188. var
  189. hp : PExceptObject;
  190. begin
  191. {$ifdef excdebug}
  192. writeln ('In PopObjectstack');
  193. {$endif}
  194. hp:=ExceptObjectStack;
  195. if hp=nil then
  196. begin
  197. {$ifdef excdebug}
  198. writeln ('At end of ExceptionObjectStack');
  199. {$endif}
  200. halt (1);
  201. end
  202. else
  203. begin
  204. { we need to return the exception object to dispose it }
  205. if hp^.refcount = 0 then
  206. fpc_PopObjectStack:=hp^.FObject
  207. else
  208. fpc_PopObjectStack:=nil;
  209. ExceptObjectStack:=hp^.next;
  210. if assigned(hp^.frames) then
  211. freemem(hp^.frames);
  212. dispose(hp);
  213. erroraddr:=nil;
  214. end;
  215. end;
  216. { this is for popping exception objects when a second exception is risen }
  217. { in an except/on }
  218. function fpc_PopSecondObjectStack : TObject;[Public, Alias : 'FPC_POPSECONDOBJECTSTACK']; compilerproc;
  219. var
  220. hp,_ExceptObjectStack : PExceptObject;
  221. begin
  222. {$ifdef excdebug}
  223. writeln ('In PopObjectstack');
  224. {$endif}
  225. _ExceptObjectStack:=ExceptObjectStack;
  226. If not(assigned(_ExceptObjectStack)) or
  227. not(assigned(_ExceptObjectStack^.next)) then
  228. begin
  229. {$ifdef excdebug}
  230. writeln ('At end of ExceptionObjectStack');
  231. {$endif}
  232. halt (1);
  233. end
  234. else
  235. begin
  236. if _ExceptObjectStack^.next^.refcount=0 then
  237. { we need to return the exception object to dispose it if refcount=0 }
  238. fpc_PopSecondObjectStack:=_ExceptObjectStack^.next^.FObject
  239. else
  240. fpc_PopSecondObjectStack:=nil;
  241. hp:=_ExceptObjectStack^.next;
  242. _ExceptObjectStack^.next:=hp^.next;
  243. if assigned(hp^.frames) then
  244. freemem(hp^.frames);
  245. dispose(hp);
  246. end;
  247. end;
  248. {$ifndef FPC_SYSTEM_HAS_RERAISE}
  249. Procedure fpc_ReRaise;[Public, Alias : 'FPC_RERAISE']; compilerproc;
  250. var
  251. _ExceptAddrStack : PExceptAddr;
  252. begin
  253. {$ifdef excdebug}
  254. writeln ('In reraise');
  255. {$endif}
  256. _ExceptAddrStack:=ExceptAddrStack;
  257. If _ExceptAddrStack=Nil then
  258. DoUnHandledException;
  259. ExceptObjectStack^.refcount := 0;
  260. longjmp(_ExceptAddrStack^.Buf^,FPC_Exception);
  261. end;
  262. {$endif FPC_SYSTEM_HAS_RERAISE}
  263. function Internal_PopSecondObjectStack : TObject; external name 'FPC_POPSECONDOBJECTSTACK';
  264. function Internal_PopObjectStack: TObject; external name 'FPC_POPOBJECTSTACK';
  265. procedure Internal_Reraise; external name 'FPC_RERAISE';
  266. Function fpc_Catches(Objtype : TClass) : TObject;[Public, Alias : 'FPC_CATCHES']; compilerproc;
  267. var
  268. _ExceptObjectStack : PExceptObject;
  269. begin
  270. _ExceptObjectStack:=ExceptObjectStack;
  271. If _ExceptObjectStack=Nil then
  272. begin
  273. {$ifdef excdebug}
  274. Writeln ('Internal error.');
  275. {$endif}
  276. halt (255);
  277. end;
  278. if Not ((Objtype = TClass(CatchAllExceptions)) or
  279. (_ExceptObjectStack^.FObject is ObjType)) then
  280. fpc_Catches:=Nil
  281. else
  282. begin
  283. // catch !
  284. fpc_Catches:=_ExceptObjectStack^.FObject;
  285. { this can't be done, because there could be a reraise (PFV)
  286. PopObjectStack;
  287. Also the PopAddrStack shouldn't be done, we do it now
  288. immediatly in the exception handler (FK)
  289. PopAddrStack; }
  290. end;
  291. end;
  292. Procedure SysInitExceptions;
  293. {
  294. Initialize exceptionsupport
  295. }
  296. begin
  297. ExceptObjectstack:=Nil;
  298. ExceptAddrStack:=Nil;
  299. end;
  300. {$ifndef FPC_SYSTEM_HAS_DONEEXCEPTION}
  301. procedure fpc_doneexception;[public,alias:'FPC_DONEEXCEPTION'] compilerproc;
  302. begin
  303. Internal_PopObjectStack.Free;
  304. end;
  305. {$endif FPC_SYSTEM_HAS_DONEEXCEPTION}
  306. {$ifndef FPC_SYSTEM_HAS_RAISENESTED}
  307. procedure fpc_raise_nested;[public,alias:'FPC_RAISE_NESTED']compilerproc;
  308. begin
  309. Internal_PopSecondObjectStack.Free;
  310. Internal_Reraise;
  311. end;
  312. {$endif FPC_SYSTEM_HAS_RAISENESTED}
  313. {$ifndef FPC_SYSTEM_HAS_SAFECALLHANDLER}
  314. function fpc_safecallhandler(obj: TObject): HResult; [public,alias:'FPC_SAFECALLHANDLER']; compilerproc;
  315. var
  316. raiselist: PExceptObject;
  317. adr: CodePointer;
  318. exc: TObject;
  319. begin
  320. raiselist:=ExceptObjectStack;
  321. if Assigned(raiseList) then
  322. adr:=raiseList^.Addr
  323. else
  324. adr:=nil;
  325. exc:=Internal_PopObjectStack;
  326. if Assigned(obj) and Assigned(exc) then
  327. result:=obj.SafeCallException(exc,adr)
  328. else
  329. result:=E_UNEXPECTED;
  330. exc.Free;
  331. end;
  332. {$endif FPC_SYSTEM_HAS_SAFECALLHANDLER}