mod.rs 11 KB

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