Resolving function calls from MIR terminators

Hi,
I'm trying to visit the complete MIR for a given function using the provided MIR Visitor. Problem is that it does not seem to resolve the function calls. Is there a way to find the target function and get the MIR in order to continue the visit?

In general, you can't. Functions may be:

  • recursive, in which case visiting again wouldn't terminate,
  • FFI, meaning that there is no MIR for the function, or
  • dynamic, meaning that it's not known exactly which function should be called.

What do you need this for?

Also in case of a generic function you may need concrete generic parameters to be able to resolve to the right function.

trait Foo {
    fn foo() {}
}

fn bar<T: Foo>() {
    T::foo(); // <-- resolving this call requires specifying what type the generic parameter T is.
}
1 Like

Thanks for your answer. I want to write a static analyzer for MIR, so recursion can probably be dealt with by using a hashmap of visited DefId. I've seen that it is possible to get extern MIR with tcx.optimized_mir(target_def_id), but I would need a way to get the target_def_id a way or another.

Thank you for your answer. Is there a way to target the correct function before monomorphization or resolve it on the fly ? I'm currently using the "after_analysis" callback on rustc-driver.

Global static analysis is not something that is usually done, exactly because it's impossible in the fully general case, and overwhelmingly hard and/or computationally unfeasible in many real-world scenarios. If you need to perform static analysis, and in particular control flow analysis, you should likely do it on the level of functions or basic blocks, not globally.

You may also be able to request that the compiler perform inlining and/or other kinds of MIR optimizations/simplifications before handing the code over to your analyzer. This would likely resolve and inline function calls when that is possible and worthwhile. I'm not familiar enough with rustc internals to be able to tell how exactly this would work, however.

1 Like

Yes I intend to do it at the extrinsic level of a FRAME pallet, which is a function level analysis. For this do_something function for example. Currently I can get the mir for this function and start to visit the basic blocks from there, but it would be nice to push the analysis to the underlying functions, so that's why I'd like to resolve those calls in the end.

First off you need to compile everything (including the standard library) with -Zalways-encode-mir to ensure MIR is available for all functions, even those not from the current crate. Then you can copy the code from the monomorphization collector adapting to not skip non-generic functions from other crates and possibly to skip constants and statics. And adapting it to consider all pallet entry points as roots. Note that the monomorphization collector doesn't just record which functions are called, but also with which generic arguments to form an Instance. The monomorphization collector can be found at rust/collector.rs at d137c3a7bd3b180317044f8ccb9a8b4b3bb07db3 · rust-lang/rust · GitHub

3 Likes

Thanks a lot! I will try this solution

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.