DWT includes "comparators" typically used as hardware watch points. My methodology was to use one of the DWT comparators to watch for something reading/writing the last u32 of the current task's stack. Note that this might not be perfect as it could be possible for the stack to somehow skip over the last u32.
Then, install a handler for the Debug Monitor exception (which triggers when a watch point is hit) to disable the DWT comparator, print/store the appropriate info, and finally reset the chip.
Essentially, we're behaving like a simple "debug monitor" which only is capable of setting a single hardware watch point automatically.
Note that DWT is technically an optional component in armv7m, so it may not be functional on every chip. That said, most folks like having debug capabilities (this is the same hardware that jtag debuggers use to set watchpoints), so most seem to include them. On that note: doing this can (to some extent) interfere with external debuggers. To mitigate some of that, I did try to use the last DWT comparator instead of the first, but this will really depend on how your debugger works.