18

My problem is simple :

  • I use Ecplise (Luna or Neon) to develop on Android and I don't want to use Android Studio

  • I wish to debug breaks on ALL unhandled exceptions only on the last user code call of the stack that cause the exception (So, for example, I don't want to break in an unuseful ZygonteInit&MethodAndArgsCaller.run() when an exception in caused by passing a null reference to a native Android SDK method).

I know that I can set a break point for a particular exception in the breakpoint view (NullPointerException..Throwable...) but I want to break on ALL unhandled. I know that I can filter debug by setting "step filters" in Java debug option, but in my case this doesn't work for all exception.

EDIT

In the image below my stack in debug View when an exception is raised (a division by zero in my code)

enter image description here

And the stack of the main thread if I set a default Uncaught Exception Handler after exception is raised.

enter image description here

christian mini
  • 1,662
  • 20
  • 39
  • 1
    I would try to do the following: 1. Implement an own custom UncoughtExceptionHandler (see [Using Global Exception Handling on android](http://stackoverflow.com/questions/4427515/using-global-exception-handling-on-android)) and 2. Use a conditional break point on that handler - for the condition check the stack trace if it contains one of your classes. – Robert Jun 20 '16 at 12:26
  • @Robert Thank you for the suggested solution. I did try this solution but the problem is that UncoughtExceptionHandler is handled by another thread while the thread that cause the exception is just ended and not available on the stack. – christian mini Jun 20 '16 at 19:30
  • @christianmini: The thread is available on the stack? There's something wrong in that sentence – Thomas Weller Jun 21 '16 at 10:52
  • @Thomas. If I set a break point into UncaughtExceptionHandler the stack of the main thread (visible in Eclipse Debug View) contains this call as leaf and ThreadGroup.uncaughtException(Thread, Throwable) as root, but not the method that cause the exception. – christian mini Jun 21 '16 at 11:55
  • You'll have to inspect the stacktrace of the exception, not the stacktrace of the place that touches them last (which is what you're looking at). Your exceptions are also not uncaught when they are thrown. There is that place in ZygoteInit that catches them before finally rethrowing them and turning them - this time - into actually uncaught exceptions. You either have to find a way to halt in like the constructor of `Throwable` so that you can stop whenever an exception is created, or you have to stop at those odd places but look at the stacktrace you still have in local variable scope. – zapl Jun 21 '16 at 12:49
  • Inspect the properties of `paramThrowable`. The callstack should be attached there. – Thomas Weller Jun 21 '16 at 13:51
  • @Thomas. I want Eclipse breaking in my code with a "live" stacktrace. So I can inspect\watch local or globlal variable value in Watch View, evaluate expression or do other debug operation. – christian mini Jun 21 '16 at 19:19
  • 1
    @christianmini: AFAIK, that's not possible with an unhandled exception handler. I've neither seen that in C++ nor in C#, so I doubt it would be possible in Java. I really wonder why breaking on "Exception" and "Throwable" is not sufficient. What exceptions are hidden? In C# for example, you can't catch StackOverflowException (and maybe a few more). – Thomas Weller Jun 22 '16 at 06:00
  • @christianmini How do you define _'but in my case this doesn't work for all exception'_? I tried setting a regular filtered breakpoint on Throwable it does suspend on Neon. – Rajeev Sreedharan Apr 27 '17 at 03:21
  • Basically I want a working "break on throw common language runtime exception" present in Visual Studio using .Net. In Visual Studio for example if I've a division by zero exception and I've "break if unhandled in user code" set, the debugger break on the user code line that cause this. I think as you said the point is: "the RuntimeException is now no more unhandled". – christian mini Apr 27 '17 at 07:12

2 Answers2

2

You can first verify if this setting in Eclipse is enabled.

Window -> Preferences -> Java -> Debug -> Suspend execution on uncaught exceptions

If this setting is enabled, any uncaught exception will suspend the JVM exactly at the point its thrown, including classes invoked using reflection. This is without adding any breakpoint, but provided its unhandled, i.e. your code is not even invoked by an external code from a try-catch.

For e.g.

int a = 0, b= 0;
System.out.println(a/b); // ArithmeticException

Even if this code is called from a reflection invoked code, eclipse will suspend at sysout with all variables still available on the stack.

However in Android's startup class ZygoteInit there is this line :

    catch (Throwable t) {
                Log.e(TAG, "Error preloading " + line + ".", t);
                if (t instanceof Error) {
                    throw (Error) t;
                }
                if (t instanceof RuntimeException) {
                    throw (RuntimeException) t;
                }
                throw new RuntimeException(t);
            }

The reason why such code would break Eclipse debugging is, the RuntimeException is now no more unhandled. Your UncaughtExceptionHandler may actually be catching the startup class instead of your user code. This is for regular Eclipse.

Solution 1 :

  1. Goto Run -> Add Java Exception Breakpoint -> Throwable
  2. Click on Throwable in the Breakpoint view
  3. Right click -> Breakpoint properties -> Add package -> OK
  4. Check on the option Subclasses of this exception

enter image description here

Note : This can marginally catch a java.lang.OutOfMemoryError but definitely cannot catch a java.lang.StackOverflowError.

Solution 2 : (Only if too many caught exceptions, NOT recommended otherwise)

  1. Copy the source code of com.android.internal.os.ZygoteInit to a new project say MyBootstrap
  2. Modify the catch (Throwable t) block to catch only Error

        } catch (Error t) {
            Log.e(TAG, "Error preloading " + line + ".", t);
            throw t;
        }
    
  3. Go-to debug configurations -> Classpath -> Click Bootstrap Entries -> Add projects -> MyBootstrap. Move this project to the top

enter image description here

Rajeev Sreedharan
  • 1,753
  • 4
  • 20
  • 30
  • I think you understand the problem: "RuntimeException is now no more unhandled", so I've to choose the parent off all Java Runtime exception, "Throwable", and I've to select "Caught Location" e "Subclass of this exception". Ok, the only problem is that during the cycle of an Android app there are hundred of Caught Exception in user code or SDK, is there a way to filter? – christian mini Apr 27 '17 at 08:10
  • @christianmini Well in that case, `catch` cannot be deterministic. How about bootstraping `ZygoteInit` with the `catch (Throwable t)` removed for debug? Since this class is for startup and does not make native calls, should be fine for a debugging. That way your unhandled exception remains unhandled. – Rajeev Sreedharan Apr 27 '17 at 08:49
  • OK, I'll also update the answer to include bootstrap incase anyone not familiar. – Rajeev Sreedharan Apr 27 '17 at 10:45
1

Basically, if I understand you correctly, you want to set a breakpoint that will trigger at the point where an exception is thrown if that exception is not / would not be handled subsequently.

If that is what you mean, then what you are asking for is basically impossible.

  1. At the point the exception is thrown the debugger cannot tell if the exception is going to be caught.

  2. At the point where the exception is caught, the state (i.e. stack frames, variables, etc) from the throw point ... and up to the catch point ... will have been discarded.

  3. The Java debugger APIs don't support a "rewind and replay" mechanism that a debugger could use for this.


To my mind, the best you can do is to 1) identify the exception that you suspect is not being caught, 2) set a breakpoint on its constructor or on a suitable superclass constructor, 3) figure out some conditions to filter out the cases that are not interesting, and 4) step through the code to see if the exception is caught or not.

Note: an exception may be thrown or rethrown at a different point to where it was instantiated, so an exception constructor breakpoint won't always help. But it usually will.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • I think there are few libraries that have `catch Throwable` for genuine reasons, but hidden deep within, causing such ambiguity during debugging. May be a similar generic case should go to SO documentation for Java/Exception. – Rajeev Sreedharan Apr 27 '17 at 10:50
  • My Answer doesn't talk about catching exceptions. And I cannot think of a legitimate reason to create an instance of `Throwable`. – Stephen C Apr 27 '17 at 11:29
  • As to the SO Documentation suggestion ... we don't yet have anything significant on debugging techniques for Java. (Apart from one example on how to read a stacktrace.) – Stephen C Apr 27 '17 at 11:30