@@ -10,8 +10,11 @@ use quote::quote;
1010use std:: collections:: HashSet ;
1111use std:: iter;
1212use syn:: {
13- parse, parse_macro_input, spanned:: Spanned , AttrStyle , Attribute , FnArg , Ident , Item , ItemFn ,
14- ItemStatic , ReturnType , Stmt , Type , Visibility ,
13+ parse:: { self , Parse } ,
14+ parse_macro_input,
15+ spanned:: Spanned ,
16+ AttrStyle , Attribute , FnArg , Ident , Item , ItemFn , ItemStatic , ReturnType , Stmt , Type ,
17+ Visibility ,
1518} ;
1619
1720#[ proc_macro_attribute]
@@ -113,21 +116,73 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
113116#[ derive( Debug , PartialEq ) ]
114117enum Exception {
115118 DefaultHandler ,
116- HardFault ,
119+ HardFault ( HardFaultArgs ) ,
117120 NonMaskableInt ,
118121 Other ,
119122}
120123
124+ #[ derive( Debug , PartialEq ) ]
125+ struct HardFaultArgs {
126+ trampoline : bool ,
127+ }
128+
129+ impl Default for HardFaultArgs {
130+ fn default ( ) -> Self {
131+ Self { trampoline : true }
132+ }
133+ }
134+
135+ impl Parse for HardFaultArgs {
136+ fn parse ( input : parse:: ParseStream ) -> syn:: Result < Self > {
137+ let mut items = Vec :: new ( ) ;
138+ // Read a list of `ident = value,`
139+ loop {
140+ if input. is_empty ( ) {
141+ break ;
142+ }
143+
144+ let name = input. parse :: < Ident > ( ) ?;
145+ input. parse :: < syn:: Token !( =) > ( ) ?;
146+ let value = input. parse :: < syn:: Lit > ( ) ?;
147+
148+ items. push ( ( name, value) ) ;
149+
150+ if input. is_empty ( ) {
151+ break ;
152+ }
153+
154+ input. parse :: < syn:: Token !( , ) > ( ) ?;
155+ }
156+
157+ let mut args = Self :: default ( ) ;
158+
159+ for ( name, value) in items {
160+ match name. to_string ( ) . as_str ( ) {
161+ "trampoline" => match value {
162+ syn:: Lit :: Bool ( val) => {
163+ args. trampoline = val. value ( ) ;
164+ }
165+ _ => {
166+ return Err ( syn:: Error :: new_spanned (
167+ value,
168+ "Not a valid value. `trampoline` takes a boolean literal" ,
169+ ) )
170+ }
171+ } ,
172+ _ => {
173+ return Err ( syn:: Error :: new_spanned ( name, "Not a valid argument name" ) ) ;
174+ }
175+ }
176+ }
177+
178+ Ok ( args)
179+ }
180+ }
181+
121182#[ proc_macro_attribute]
122183pub fn exception ( args : TokenStream , input : TokenStream ) -> TokenStream {
123184 let mut f = parse_macro_input ! ( input as ItemFn ) ;
124185
125- if !args. is_empty ( ) {
126- return parse:: Error :: new ( Span :: call_site ( ) , "This attribute accepts no arguments" )
127- . to_compile_error ( )
128- . into ( ) ;
129- }
130-
131186 if let Err ( error) = check_attr_whitelist ( & f. attrs , WhiteListCaller :: Exception ) {
132187 return error;
133188 }
@@ -137,14 +192,34 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
137192
138193 let ident_s = ident. to_string ( ) ;
139194 let exn = match & * ident_s {
140- "DefaultHandler" => Exception :: DefaultHandler ,
141- "HardFault" => Exception :: HardFault ,
142- "NonMaskableInt" => Exception :: NonMaskableInt ,
195+ "DefaultHandler" => {
196+ if !args. is_empty ( ) {
197+ return parse:: Error :: new ( Span :: call_site ( ) , "This attribute accepts no arguments" )
198+ . to_compile_error ( )
199+ . into ( ) ;
200+ }
201+ Exception :: DefaultHandler
202+ }
203+ "HardFault" => Exception :: HardFault ( parse_macro_input ! ( args) ) ,
204+ "NonMaskableInt" => {
205+ if !args. is_empty ( ) {
206+ return parse:: Error :: new ( Span :: call_site ( ) , "This attribute accepts no arguments" )
207+ . to_compile_error ( )
208+ . into ( ) ;
209+ }
210+ Exception :: NonMaskableInt
211+ }
143212 // NOTE that at this point we don't check if the exception is available on the target (e.g.
144213 // MemoryManagement is not available on Cortex-M0)
145214 "MemoryManagement" | "BusFault" | "UsageFault" | "SecureFault" | "SVCall"
146215 | "DebugMonitor" | "PendSV" | "SysTick" => Exception :: Other ,
147216 _ => {
217+ if !args. is_empty ( ) {
218+ return parse:: Error :: new ( Span :: call_site ( ) , "This attribute accepts no arguments" )
219+ . to_compile_error ( )
220+ . into ( ) ;
221+ }
222+
148223 return parse:: Error :: new ( ident. span ( ) , "This is not a valid exception name" )
149224 . to_compile_error ( )
150225 . into ( ) ;
@@ -153,7 +228,7 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
153228
154229 if f. sig . unsafety . is_none ( ) {
155230 match exn {
156- Exception :: DefaultHandler | Exception :: HardFault | Exception :: NonMaskableInt => {
231+ Exception :: DefaultHandler | Exception :: HardFault ( _ ) | Exception :: NonMaskableInt => {
157232 // These are unsafe to define.
158233 let name = if exn == Exception :: DefaultHandler {
159234 "`DefaultHandler`" . to_string ( )
@@ -232,17 +307,24 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
232307 #f
233308 )
234309 }
235- Exception :: HardFault if cfg ! ( feature = "hardfault-trampoline" ) => {
310+ Exception :: HardFault ( args ) => {
236311 let valid_signature = f. sig . constness . is_none ( )
237312 && f. vis == Visibility :: Inherited
238313 && f. sig . abi . is_none ( )
239- && f. sig . inputs . len ( ) == 1
240- && match & f. sig . inputs [ 0 ] {
241- FnArg :: Typed ( arg) => match arg. ty . as_ref ( ) {
242- Type :: Reference ( r) => r. lifetime . is_none ( ) && r. mutability . is_none ( ) ,
314+ && if args. trampoline {
315+ match & f. sig . inputs [ 0 ] {
316+ FnArg :: Typed ( arg) => match arg. ty . as_ref ( ) {
317+ Type :: Reference ( r) => {
318+ r. lifetime . is_none ( )
319+ && r. mutability . is_none ( )
320+ && f. sig . inputs . len ( ) == 1
321+ }
322+ _ => false ,
323+ } ,
243324 _ => false ,
244- } ,
245- _ => false ,
325+ }
326+ } else {
327+ f. sig . inputs . is_empty ( )
246328 }
247329 && f. sig . generics . params . is_empty ( )
248330 && f. sig . generics . where_clause . is_none ( )
@@ -255,66 +337,74 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
255337 if !valid_signature {
256338 return parse:: Error :: new (
257339 fspan,
258- "`HardFault` handler must have signature `unsafe fn(&ExceptionFrame) -> !`" ,
340+ if args. trampoline {
341+ "`HardFault` handler must have signature `unsafe fn(&ExceptionFrame) -> !`"
342+ } else {
343+ "`HardFault` handler must have signature `unsafe fn() -> !`"
344+ } ,
259345 )
260346 . to_compile_error ( )
261347 . into ( ) ;
262348 }
263349
264350 f. sig . ident = Ident :: new ( & format ! ( "__cortex_m_rt_{}" , f. sig. ident) , Span :: call_site ( ) ) ;
265- let tramp_ident = Ident :: new ( & format ! ( "{}_trampoline" , f. sig. ident) , Span :: call_site ( ) ) ;
266- let ident = & f. sig . ident ;
267351
268- let ( ref cfgs, ref attrs) = extract_cfgs ( f. attrs . clone ( ) ) ;
352+ if args. trampoline {
353+ let tramp_ident =
354+ Ident :: new ( & format ! ( "{}_trampoline" , f. sig. ident) , Span :: call_site ( ) ) ;
355+ let ident = & f. sig . ident ;
269356
270- quote ! (
271- #( #cfgs) *
272- #( #attrs) *
273- #[ doc( hidden) ]
274- #[ export_name = "HardFault" ]
275- // Only emit link_section when building for embedded targets,
276- // because some hosted platforms (used to check the build)
277- // cannot handle the long link section names.
278- #[ cfg_attr( target_os = "none" , link_section = ".HardFault.user" ) ]
279- pub unsafe extern "C" fn #tramp_ident( frame: & :: cortex_m_rt:: ExceptionFrame ) {
280- #ident( frame)
281- }
357+ let ( ref cfgs, ref attrs) = extract_cfgs ( f. attrs . clone ( ) ) ;
282358
283- #f
284- )
285- }
286- Exception :: HardFault => {
287- let valid_signature = f. sig . constness . is_none ( )
288- && f. vis == Visibility :: Inherited
289- && f. sig . abi . is_none ( )
290- && f. sig . inputs . is_empty ( )
291- && f. sig . generics . params . is_empty ( )
292- && f. sig . generics . where_clause . is_none ( )
293- && f. sig . variadic . is_none ( )
294- && match f. sig . output {
295- ReturnType :: Default => false ,
296- ReturnType :: Type ( _, ref ty) => matches ! ( * * ty, Type :: Never ( _) ) ,
297- } ;
359+ quote ! (
360+ #( #cfgs) *
361+ #( #attrs) *
362+ #[ doc( hidden) ]
363+ #[ export_name = "HardFault" ]
364+ // Only emit link_section when building for embedded targets,
365+ // because some hosted platforms (used to check the build)
366+ // cannot handle the long link section names.
367+ #[ cfg_attr( target_os = "none" , link_section = ".HardFault.user" ) ]
368+ pub unsafe extern "C" fn #tramp_ident( frame: & :: cortex_m_rt:: ExceptionFrame ) {
369+ #ident( frame)
370+ }
298371
299- if !valid_signature {
300- return parse:: Error :: new (
301- fspan,
302- "`HardFault` handler must have signature `unsafe fn() -> !`" ,
372+ #f
373+
374+ // HardFault exceptions are bounced through this trampoline which grabs the stack pointer at
375+ // the time of the exception and passes it to the user's HardFault handler in r0.
376+ // Depending on the stack mode in EXC_RETURN, fetches stack from either MSP or PSP.
377+ core:: arch:: global_asm!(
378+ ".cfi_sections .debug_frame
379+ .section .HardFaultTrampoline, \" ax\"
380+ .global HardFaultTrampline
381+ .type HardFaultTrampline,%function
382+ .thumb_func
383+ .cfi_startproc
384+ HardFaultTrampoline:" ,
385+ "mov r0, lr
386+ movs r1, #4
387+ tst r0, r1
388+ bne 0f
389+ mrs r0, MSP
390+ b HardFault
391+ 0:
392+ mrs r0, PSP
393+ b HardFault" ,
394+ ".cfi_endproc
395+ .size HardFaultTrampoline, . - HardFaultTrampoline" ,
396+ ) ;
397+ )
398+ } else {
399+ quote ! (
400+ #[ export_name = "HardFault" ]
401+ // Only emit link_section when building for embedded targets,
402+ // because some hosted platforms (used to check the build)
403+ // cannot handle the long link section names.
404+ #[ cfg_attr( target_os = "none" , link_section = ".HardFault.user" ) ]
405+ #f
303406 )
304- . to_compile_error ( )
305- . into ( ) ;
306407 }
307-
308- f. sig . ident = Ident :: new ( & format ! ( "__cortex_m_rt_{}" , f. sig. ident) , Span :: call_site ( ) ) ;
309-
310- quote ! (
311- #[ export_name = "HardFault" ]
312- // Only emit link_section when building for embedded targets,
313- // because some hosted platforms (used to check the build)
314- // cannot handle the long link section names.
315- #[ cfg_attr( target_os = "none" , link_section = ".HardFault.user" ) ]
316- #f
317- )
318408 }
319409 Exception :: NonMaskableInt | Exception :: Other => {
320410 let valid_signature = f. sig . constness . is_none ( )
0 commit comments