mod.rs 11 KB

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