rustc provides a number of tools to debug general syntax extensions, as well as some more specific ones tailored towards declarative and procedural macros respectively.

Sometimes, it is what the extension expands to that proves problematic as you do not usually see the expanded code. Fortunately rustc offers the ability to look at the expanded code, for this, the --pretty argument can be used. Given the following code:

// Shorthand for initializing a `String`.
macro_rules! S {
    ($e:expr) => {String::from($e)};

fn main() {
    let world = S!("World");
    println!("Hello, {}!", world);

compiled with the following command:

rustc -Z unstable-options -Zunpretty=expanded

produces the following output (modified for formatting):

use std::prelude::rust_2018::*;
extern crate std;
// Shorthand for initializing a `String`.
macro_rules! S { ($e : expr) => { String :: from($e) } ; }

fn main() {
    let world = String::from("World");
                &["Hello, ", "!\n"],
                &match (&world,) {
                    (arg0,) => [
                        ::core::fmt::ArgumentV1::new(arg0, ::core::fmt::Display::fmt)

But not just rustc exposes means to aid in debugging syntax extensions. For the aforementioned --pretty=expanded option, there exists a nice cargo plugin called cargo-expand made by dtolnay which is basically just a wrapper around it.

You can also use the playground, clicking on its TOOLS button in the top right gives you the option to expand syntax extensions as well!