abi.rs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. use core::ffi::c_void;
  2. use core::ops;
  3. use core::ptr;
  4. use gimli::Register;
  5. use crate::arch::*;
  6. use crate::find_fde::{self, FDEFinder};
  7. use crate::frame::Frame;
  8. use crate::util::*;
  9. #[repr(transparent)]
  10. #[derive(Clone, Copy, PartialEq, Eq)]
  11. pub struct UnwindReasonCode(c_int);
  12. #[allow(unused)]
  13. impl UnwindReasonCode {
  14. pub const NO_REASON: Self = Self(0);
  15. pub const FOREIGN_EXCEPTION_CAUGHT: Self = Self(1);
  16. pub const FATAL_PHASE2_ERROR: Self = Self(2);
  17. pub const FATAL_PHASE1_ERROR: Self = Self(3);
  18. pub const NORMAL_STOP: Self = Self(4);
  19. pub const END_OF_STACK: Self = Self(5);
  20. pub const HANDLER_FOUND: Self = Self(6);
  21. pub const INSTALL_CONTEXT: Self = Self(7);
  22. pub const CONTINUE_UNWIND: Self = Self(8);
  23. }
  24. #[repr(transparent)]
  25. #[derive(Clone, Copy, PartialEq, Eq)]
  26. pub struct UnwindAction(c_int);
  27. impl UnwindAction {
  28. pub const SEARCH_PHASE: Self = Self(1);
  29. pub const CLEANUP_PHASE: Self = Self(2);
  30. pub const HANDLER_FRAME: Self = Self(4);
  31. pub const FORCE_UNWIND: Self = Self(8);
  32. pub const END_OF_STACK: Self = Self(16);
  33. }
  34. impl ops::BitOr for UnwindAction {
  35. type Output = Self;
  36. #[inline]
  37. fn bitor(self, rhs: Self) -> Self {
  38. Self(self.0 | rhs.0)
  39. }
  40. }
  41. impl UnwindAction {
  42. #[inline]
  43. pub const fn empty() -> Self {
  44. Self(0)
  45. }
  46. #[inline]
  47. pub const fn contains(&self, other: Self) -> bool {
  48. self.0 & other.0 != 0
  49. }
  50. }
  51. pub type UnwindExceptionCleanupFn = unsafe extern "C" fn(UnwindReasonCode, *mut UnwindException);
  52. pub type UnwindStopFn = unsafe extern "C" fn(
  53. c_int,
  54. UnwindAction,
  55. u64,
  56. &mut UnwindException,
  57. &mut UnwindContext<'_>,
  58. *mut c_void,
  59. ) -> UnwindReasonCode;
  60. #[repr(C)]
  61. pub struct UnwindException {
  62. pub exception_class: u64,
  63. pub exception_cleanup: Option<UnwindExceptionCleanupFn>,
  64. private_1: Option<UnwindStopFn>,
  65. private_2: usize,
  66. private_unused: [usize; Arch::UNWIND_PRIVATE_DATA_SIZE - 2],
  67. }
  68. pub type UnwindTraceFn =
  69. unsafe extern "C" fn(ctx: &mut UnwindContext<'_>, arg: *mut c_void) -> UnwindReasonCode;
  70. pub struct UnwindContext<'a> {
  71. frame: Option<&'a Frame>,
  72. ctx: &'a mut Context,
  73. }
  74. pub type PersonalityRoutine = extern "C" fn(
  75. c_int,
  76. UnwindAction,
  77. u64,
  78. &mut UnwindException,
  79. &mut UnwindContext<'_>,
  80. ) -> UnwindReasonCode;
  81. #[no_mangle]
  82. pub extern "C" fn _Unwind_GetGR(unwind_ctx: &UnwindContext<'_>, index: c_int) -> usize {
  83. unwind_ctx.ctx[Register(index as u16)]
  84. }
  85. #[no_mangle]
  86. pub extern "C" fn _Unwind_GetCFA(unwind_ctx: &UnwindContext<'_>) -> usize {
  87. unwind_ctx.ctx[Arch::SP]
  88. }
  89. #[no_mangle]
  90. pub extern "C" fn _Unwind_SetGR(unwind_ctx: &mut UnwindContext<'_>, index: c_int, value: usize) {
  91. unwind_ctx.ctx[Register(index as u16)] = value;
  92. }
  93. #[no_mangle]
  94. pub extern "C" fn _Unwind_GetIP(unwind_ctx: &UnwindContext<'_>) -> usize {
  95. unwind_ctx.ctx[Arch::RA]
  96. }
  97. #[no_mangle]
  98. pub extern "C" fn _Unwind_GetIPInfo(
  99. unwind_ctx: &UnwindContext<'_>,
  100. ip_before_insn: &mut c_int,
  101. ) -> usize {
  102. *ip_before_insn = 0;
  103. unwind_ctx.ctx[Arch::RA]
  104. }
  105. #[no_mangle]
  106. pub extern "C" fn _Unwind_SetIP(unwind_ctx: &mut UnwindContext<'_>, value: usize) {
  107. unwind_ctx.ctx[Arch::RA] = value;
  108. }
  109. #[no_mangle]
  110. pub extern "C" fn _Unwind_GetLanguageSpecificData(unwind_ctx: &UnwindContext<'_>) -> *mut c_void {
  111. unwind_ctx
  112. .frame
  113. .map(|f| f.lsda() as *mut c_void)
  114. .unwrap_or(ptr::null_mut())
  115. }
  116. #[no_mangle]
  117. pub extern "C" fn _Unwind_GetRegionStart(unwind_ctx: &UnwindContext<'_>) -> usize {
  118. unwind_ctx.frame.map(|f| f.initial_address()).unwrap_or(0)
  119. }
  120. #[no_mangle]
  121. pub extern "C" fn _Unwind_GetTextRelBase(unwind_ctx: &UnwindContext<'_>) -> usize {
  122. unwind_ctx
  123. .frame
  124. .map(|f| f.bases().eh_frame.text.unwrap() as _)
  125. .unwrap_or(0)
  126. }
  127. #[no_mangle]
  128. pub extern "C" fn _Unwind_GetDataRelBase(unwind_ctx: &UnwindContext<'_>) -> usize {
  129. unwind_ctx
  130. .frame
  131. .map(|f| f.bases().eh_frame.data.unwrap() as _)
  132. .unwrap_or(0)
  133. }
  134. #[no_mangle]
  135. pub extern "C" fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void {
  136. find_fde::get_finder()
  137. .find_fde(pc as usize - 1)
  138. .map(|r| r.fde.initial_address() as usize as _)
  139. .unwrap_or(ptr::null_mut())
  140. }
  141. macro_rules! try1 {
  142. ($e: expr) => {{
  143. match $e {
  144. Ok(v) => v,
  145. Err(_) => return UnwindReasonCode::FATAL_PHASE1_ERROR,
  146. }
  147. }};
  148. }
  149. macro_rules! try2 {
  150. ($e: expr) => {{
  151. match $e {
  152. Ok(v) => v,
  153. Err(_) => return UnwindReasonCode::FATAL_PHASE2_ERROR,
  154. }
  155. }};
  156. }
  157. #[no_mangle]
  158. pub extern "C-unwind" fn _Unwind_RaiseException(
  159. exception: &mut UnwindException,
  160. ) -> UnwindReasonCode {
  161. let saved_ctx = save_context();
  162. // Phase 1: Search for handler
  163. let mut ctx = saved_ctx.clone();
  164. let handler_cfa = loop {
  165. if let Some(frame) = try1!(Frame::from_context(&ctx)) {
  166. if let Some(personality) = frame.personality() {
  167. let result = personality(
  168. 1,
  169. UnwindAction::SEARCH_PHASE,
  170. exception.exception_class,
  171. exception,
  172. &mut UnwindContext {
  173. frame: Some(&frame),
  174. ctx: &mut ctx,
  175. },
  176. );
  177. match result {
  178. UnwindReasonCode::CONTINUE_UNWIND => (),
  179. UnwindReasonCode::HANDLER_FOUND => {
  180. exception.private_1 = None;
  181. exception.private_2 = ctx[Arch::SP];
  182. break ctx[Arch::SP];
  183. }
  184. _ => return UnwindReasonCode::FATAL_PHASE1_ERROR,
  185. }
  186. }
  187. ctx = try1!(frame.unwind(&ctx));
  188. } else {
  189. return UnwindReasonCode::END_OF_STACK;
  190. }
  191. };
  192. let mut ctx = saved_ctx;
  193. let code = raise_exception_phase2(exception, &mut ctx, handler_cfa);
  194. match code {
  195. UnwindReasonCode::INSTALL_CONTEXT => unsafe { restore_context(&ctx) },
  196. _ => code,
  197. }
  198. }
  199. fn raise_exception_phase2(
  200. exception: &mut UnwindException,
  201. ctx: &mut Context,
  202. handler_cfa: usize,
  203. ) -> UnwindReasonCode {
  204. loop {
  205. if let Some(frame) = try2!(Frame::from_context(ctx)) {
  206. let is_handler = ctx[Arch::SP] == handler_cfa;
  207. if let Some(personality) = frame.personality() {
  208. let code = personality(
  209. 1,
  210. UnwindAction::CLEANUP_PHASE
  211. | if is_handler {
  212. UnwindAction::HANDLER_FRAME
  213. } else {
  214. UnwindAction::empty()
  215. },
  216. exception.exception_class,
  217. exception,
  218. &mut UnwindContext {
  219. frame: Some(&frame),
  220. ctx,
  221. },
  222. );
  223. match code {
  224. UnwindReasonCode::CONTINUE_UNWIND => (),
  225. UnwindReasonCode::INSTALL_CONTEXT => break,
  226. _ => return UnwindReasonCode::FATAL_PHASE2_ERROR,
  227. }
  228. }
  229. *ctx = try2!(frame.unwind(ctx));
  230. } else {
  231. return UnwindReasonCode::FATAL_PHASE2_ERROR;
  232. }
  233. }
  234. UnwindReasonCode::INSTALL_CONTEXT
  235. }
  236. #[no_mangle]
  237. pub unsafe extern "C-unwind" fn _Unwind_ForceUnwind(
  238. exception: &mut UnwindException,
  239. stop: UnwindStopFn,
  240. stop_arg: *mut c_void,
  241. ) -> UnwindReasonCode {
  242. let mut ctx = save_context();
  243. exception.private_1 = Some(stop);
  244. exception.private_2 = stop_arg as _;
  245. let code = unsafe { force_unwind_phase2(exception, &mut ctx, stop, stop_arg) };
  246. match code {
  247. UnwindReasonCode::INSTALL_CONTEXT => unsafe { restore_context(&ctx) },
  248. _ => code,
  249. }
  250. }
  251. unsafe fn force_unwind_phase2(
  252. exception: &mut UnwindException,
  253. ctx: &mut Context,
  254. stop: UnwindStopFn,
  255. stop_arg: *mut c_void,
  256. ) -> UnwindReasonCode {
  257. loop {
  258. let frame = try2!(Frame::from_context(ctx));
  259. let code = unsafe {
  260. stop(
  261. 1,
  262. UnwindAction::FORCE_UNWIND
  263. | UnwindAction::END_OF_STACK
  264. | if frame.is_none() {
  265. UnwindAction::END_OF_STACK
  266. } else {
  267. UnwindAction::empty()
  268. },
  269. exception.exception_class,
  270. exception,
  271. &mut UnwindContext {
  272. frame: frame.as_ref(),
  273. ctx,
  274. },
  275. stop_arg,
  276. )
  277. };
  278. match code {
  279. UnwindReasonCode::NO_REASON => (),
  280. _ => return UnwindReasonCode::FATAL_PHASE2_ERROR,
  281. }
  282. if let Some(frame) = frame {
  283. if let Some(personality) = frame.personality() {
  284. let code = personality(
  285. 1,
  286. UnwindAction::FORCE_UNWIND | UnwindAction::CLEANUP_PHASE,
  287. exception.exception_class,
  288. exception,
  289. &mut UnwindContext {
  290. frame: Some(&frame),
  291. ctx,
  292. },
  293. );
  294. match code {
  295. UnwindReasonCode::CONTINUE_UNWIND => (),
  296. UnwindReasonCode::INSTALL_CONTEXT => break,
  297. _ => return UnwindReasonCode::FATAL_PHASE2_ERROR,
  298. }
  299. }
  300. *ctx = try2!(frame.unwind(ctx));
  301. } else {
  302. return UnwindReasonCode::END_OF_STACK;
  303. }
  304. }
  305. UnwindReasonCode::INSTALL_CONTEXT
  306. }
  307. #[no_mangle]
  308. pub extern "C-unwind" fn _Unwind_Resume(exception: &mut UnwindException) -> ! {
  309. let mut ctx = save_context();
  310. let code = match exception.private_1 {
  311. None => {
  312. let handler_cfa = exception.private_2;
  313. raise_exception_phase2(exception, &mut ctx, handler_cfa)
  314. }
  315. Some(stop) => {
  316. let stop_arg = exception.private_2 as _;
  317. unsafe { force_unwind_phase2(exception, &mut ctx, stop, stop_arg) }
  318. }
  319. };
  320. assert!(code == UnwindReasonCode::INSTALL_CONTEXT);
  321. unsafe { restore_context(&ctx) }
  322. }
  323. #[no_mangle]
  324. pub extern "C-unwind" fn _Unwind_Resume_or_Rethrow(
  325. exception: &mut UnwindException,
  326. ) -> UnwindReasonCode {
  327. let stop = match exception.private_1 {
  328. None => return _Unwind_RaiseException(exception),
  329. Some(v) => v,
  330. };
  331. let mut ctx = save_context();
  332. let stop_arg = exception.private_2 as _;
  333. let code = unsafe { force_unwind_phase2(exception, &mut ctx, stop, stop_arg) };
  334. assert!(code == UnwindReasonCode::INSTALL_CONTEXT);
  335. unsafe { restore_context(&ctx) }
  336. }
  337. #[no_mangle]
  338. pub unsafe extern "C" fn _Unwind_DeleteException(exception: *mut UnwindException) {
  339. if let Some(cleanup) = unsafe { (*exception).exception_cleanup } {
  340. unsafe { cleanup(UnwindReasonCode::FOREIGN_EXCEPTION_CAUGHT, exception) };
  341. }
  342. }
  343. #[no_mangle]
  344. pub unsafe extern "C-unwind" fn _Unwind_Backtrace(
  345. trace: UnwindTraceFn,
  346. trace_argument: *mut c_void,
  347. ) -> UnwindReasonCode {
  348. let mut ctx = save_context();
  349. let mut skipping = cfg!(feature = "hide-trace");
  350. loop {
  351. let frame = try1!(Frame::from_context(&ctx));
  352. if !skipping {
  353. let code = unsafe {
  354. trace(
  355. &mut UnwindContext {
  356. frame: frame.as_ref(),
  357. ctx: &mut ctx,
  358. },
  359. trace_argument,
  360. )
  361. };
  362. match code {
  363. UnwindReasonCode::NO_REASON => (),
  364. _ => return UnwindReasonCode::FATAL_PHASE1_ERROR,
  365. }
  366. }
  367. if let Some(frame) = frame {
  368. if skipping {
  369. if frame.initial_address() == _Unwind_Backtrace as usize {
  370. skipping = false;
  371. }
  372. }
  373. ctx = try1!(frame.unwind(&ctx));
  374. } else {
  375. return UnwindReasonCode::END_OF_STACK;
  376. }
  377. }
  378. }