You COULD catch it in any of those places. Keep in mind that if something in D fails and you catch it, handle it then continue, everything will continue on happily thru the rest of the execution of C,B and A. So.. you need to make sure that you have some means of notifying calling functions in the event you catch a handlable exception.
Here is what I do for these sorts of things...
I have created a virtual class called BaseReturnArgs. It contains a boolean property "Success", a string property "ErrorMessage" and a System.Exception property "Exception". Then for whatever I'm doing (lets say I'm writing a data controller that returns a DataTable), I create a class that is derived from BaseReturnArgs, and I call it MyDataReturnArgs where "MyData" is something more meaningfull, like "GetUsers" etc. Then my function returns my customized return args object. So can then call my methods and get back that object, check to see if it succeeded, then do what I want with either the ErrorMessage or the inner exception.
The advantage to this is that I can handle things differently based on what is returned in that object: If InnerException is Nothing/null then I can check the ErrorMessage. This gives me the ability to use a "Fail" state for expected errors ("User doesn't exist", "Bad login", etc.).