22 Nov 2010

JavaCard applets debugging techniques

Debugging JavaCard applets is always difficult. There are different ways of debugging applets:
  • Usage of different simulators
  • Usage of On Card Debugger
  • Applet way of debugging

Let’s review each way one by one.

Simulators
Most of JavaCard development IDEs provides SIM Card Simulator. Two of them are bundled with JavaCard Development Kit. They are CREF and JCWDE. I couldn’t tell too much about them as I’ve never used. Another example is commercial product Developer Suite by Gemalto. It has own different type simulators. Which enables you to debug different applets including Smart Card Web Server (SCWS) servlets and NFC applets.
The simulators are good enough but sometimes you need to debug on real card. The situation when everything is working fine on simulator and not working on the card isn’t rare.
I don’t want to pay a lot attention to simulator as debugging techniques are almost the same as any other application.

On Card Debugger
This is most advanced way of debugging applets but at the same time least available. Each SmartCard manufacturer has own On Card Debugger implementation and usage of it is subject of property. It is not available outside of the manufacturer.
But anyway let me explain general approach of On Card Debugger usage. Most of them are based on Remote Java Debugging. To use it you have to follow below actions:

  • Compile your applet with Debug_Component (Be careful, Debug_Component is only available starting from JavaCard 2.2.1). To be able to do it you have to compile all your classes with debug information and use –debug option during conversion
  • Load applet to the card
  • Setup your favourite development environment for Remote Java Debugging
  • Activate On Card Debugger if needed

I can’t say more on this subject as I have NDA constraints.

Applet way of debugging
This way is most available. The general idea is the same as logging your application steps. I’d like to cover it in details.
There are several ways of applet way of debugging:

  • Throw ISOException.throwIt(0x????) if some verification didn’t pass. As a result you’ll have Status Word for some action of your applet and you can figure out what is going wrong
  • Usage DISPLAY TEXT proactive command to track your applet execution
  • Usage of Shareable interface and communicate with your applet from another one and somehow get execution steps. Here you can use DISPLAY TEXT or you can write to some file.
  • Usage of Debug file directly from your applet. You can write logs to this file
  • You can create your own APDU commands and implement process() method
  • Combination of above steps

Personally I prefer combination of DISPLAY TEXT and creation of own APDUs with implementation of process() method.

Let’s review this method step by step.

The main idea of this debugging techniques is writing specific values to global variables at different part of the code execution and retrieve those values when needed.

With these values we can deduce:

  • The last correctly executed line
  • What kind of exception has thrown and and its reason

We can retrieve those values in 2 different ways:

  • By selection of STK menu
  • By selecting directly applet AID and send appropriate APDU

How can we implement it? We can declare bunch of static variables to store debug values like:

private static byte bDebug1 = (byte)0;
private static byte bDebug2 = (byte)0;
private static byte bDebug3 = (byte)0;
private static byte bDebug4 = (byte)0;
private static byte bDebug5 = (byte)0;
private static byte bDebug6 = (byte)0;

Then we need to implement setDebug() method like:

private static void setDebug( short sDebug )
{
    bDebug1 = (byte) (sDebug >> 8);
    bDebug2 = (byte) sDebug;
}
private static void setDebug( short sDebug, short sDebug2 )
{
    bDebug3 = (byte) (sDebug >> 8);
    bDebug4 = (byte) sDebug;
    bDebug5 = (byte) (sDebug2 >> 8);
    bDebug6 = (byte) sDebug2;
}

Now in our target applet which we have to debug we can use it like:

setDebug((short)0x0102);

Where 0x0102 is some coding which specify whatever you want on some stage of execution.

To retrieve values we have to implement process() method like:

/**
* Method called by the JCRE, once selected
* @param apdu the incoming APDU object
*/
public void process(APDU apdu) {
    /** any APDU command to the applet will send back 6 bytes */
    byte [] baAPDU = apdu.getBuffer();

    baAPDU[ ISO7816.OFFSET_CDATA ] = bDebug1;
    baAPDU[ ISO7816.OFFSET_CDATA + 1 ] = bDebug2;
    baAPDU[ ISO7816.OFFSET_CDATA + 2 ] = bDebug3;
    baAPDU[ ISO7816.OFFSET_CDATA + 3 ] = bDebug4;
    baAPDU[ ISO7816.OFFSET_CDATA + 4 ] = bDebug5;
    baAPDU[ ISO7816.OFFSET_CDATA + 5 ] = bDebug6;

    apdu.setOutgoingAndSend( ISO7816.OFFSET_CDATA, (short) 6 );
}

To retrieve debug information through STK menu we have to implement processToolkit() method:

/**
* Method called by the SIM Toolkit Framework
* @param event the byte representation of the event triggered
*/
public void processToolkit(byte event) {
    try {
        EnvelopeHandler envHdlr = EnvelopeHandler.getTheHandler();

        // Manage the request following the MENU SELECTION event type
        if (event == EVENT_MENU_SELECTION) {
            // Get the selected item
            byte selectedItemId = envHdlr.getItemIdentifier();

            // Perform the required service following the Menu1 selected item
            if (selectedItemId == idMenuDisplayDebug) {
                displayDebug();
            }
        }

        // If required by your applet implement managing
        // UNFORMATTED SMS PP ENV event type and
        // FORMATTED SMS PP event type

       if (event == EVENT_UNFORMATTED_SMS_PP_ENV) {
           unformattedSmsDownloadService();
       }
       if (event == EVENT_FORMATTED_SMS_PP_ENV) {
           formattedSmsDownloadService();
       }
    }
    catch(ArrayIndexOutOfBoundsException aioob) {
        setDebug((short)0x0100, (short)0x1111);
    }
    catch(NullPointerException npe) {
        setDebug((short)0x0200, (short)0x1111);
    }
    catch(SecurityException se) {
        setDebug((short)0x0300, (short)0x1111);
    }
    catch(ISOException ie) {
        setDebug((short)0x0400, ie.getReason());
    }
    catch(SIMViewException sve) {
        setDebug((short)0x0500, sve.getReason());
    }
    catch(ToolkitException te) {
        setDebug((short)0x0600, te.getReason());
    }
    //
    // add here any other exceptions
    //
    catch(Exception e) {
        setDebug((short)0x0700, (short)0x1111);
    }
}

The displayDebug() method could be implemented like:

/**
* Manage the debug menu selection
*/
private void displayDebug() {
// Get the received envelope
ProactiveHandler proHdlr = ProactiveHandler.getTheHandler();

baStringDebug[(short)0] = bDebug1;
baStringDebug[(short)1] = bDebug2;
baStringDebug[(short)2] = bDebug3;
baStringDebug[(short)3] = bDebug4;
baStringDebug[(short)4] = bDebug5;
baStringDebug[(short)5] = bDebug6;

// Display the "Menu3" message text
// Initialize the display text command
proHdlr.initDisplayText((byte) 0x00
, DCS_8_BIT_DATA
, baStringDebug
, (short) 0
,(short) (baStringDebug.length));
proHdlr.send();

return;
}

Happy debug! :)

5 comments:

Praveen PPT said...

Hi im trying to debug my applet on gemalto dev suite can u send me the basic applet explaining hw to use the process explained by you...

Anonymous said...

Hi im trying to debug my applet on gemalto dev suite can u send me the basic applet explaining hw to use the process explained by you...
praveenteragaonkar@gmail.com

Nodir Gulyamov said...

Hi,
You can do it easily on your side. Just generate sample applet using Dev Suite. The wizard will ask you several parameters then generate fully functional applet. Afterwards you have to change process() method for debugging using explicit selection of applet and processToolkit() method for debugging using Display Text. If you'll have difficulties feel free to ask.

Praveen PPT said...

Hi,
Thanks for the reply...
Your process method will provide oly the bDebug1-6 values which you hav set previously but where as i want to know the value of my variable in the code at some point of time during execution on card so is der is any way to get values at specified line on card???

Nodir Gulyamov said...

Hi,
bDebug variables is just predefined ones which is example. Nothing prevent you to improve this technique by adding additional variables and assign interested values to them and check after.