I am developing Android-Disassembler. I need to optimize the loop below.
It is currectly calling native method for each instructions(about 4 bytes). So this loop will be looped about millions of times while disassembling the entire code section.
The code below is what I was using.
private void DisassembleFile()
{
Toast.makeText(this, "started", 2).show();
Log.v(TAG, "Strted disassm");
//final ProgressDialog dialog= showProgressDialog("Disassembling...");
disasmResults.clear();
mNotifyManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mBuilder = new Notification.Builder(this);
mBuilder.setContentTitle("Disassembler")
.setContentText("Disassembling in progress")
.setSmallIcon(R.drawable.cell_shape)
.setOngoing(true)
.setProgress(100, 0, false);
workerThread = new Thread(new Runnable(){
@Override
public void run()
{
long start=elfUtil.getCodeSectionOffset();
long index=start;
long limit=elfUtil.getCodeSectionLimit();
long addr=elfUtil.getCodeSectionVirtAddr();
Log.v(TAG, "code section point :" + Long.toHexString(index));
HashMap xrefComments=new HashMap();
for (;;)
{
Capstone.CsInsn[] insns=cs.disasm(filecontent,index,addr,1);
Capstone.CsInsn insn=insns[0];
final ListViewItem lvi=new ListViewItem(insn);
if (insn.size == 0)
{
insn.size = 4;
insn.mnemonic = "db";
//insn.bytes = new byte[]{filecontent[(int)index],filecontent[(int)index + 1],filecontent[(int)index + 2],filecontent[(int)index + 3]};
insn.opStr = "";
Log.e(TAG, "Dar.size==0, breaking?");
//break;
}
runOnUiThread(new Runnable(){
@Override
public void run()
{
adapter.addItem(lvi);
adapter.notifyDataSetChanged();
return ;
}
});
//Log.v(TAG, "i=" + index + "lvi=" + lvi.toString());
if (index >= limit)
{
Log.i(TAG, "index is " + index + ", breaking");
break;
}
Log.i(TAG, "" + index + " out of " + (limit - start));
if ((index - start) % 320 == 0)
{
mBuilder.setProgress((int)(limit - start), (int)(index - start), false);
// Displays the progress bar for the first time.
mNotifyManager.notify(0, mBuilder.build());
runOnUiThread(new Runnable(){
@Override
public void run()
{
//adapter.notifyDataSetChanged();
listview.requestLayout();
}
});
}
index += insn.size;
addr += insn.size;
//dialog.setProgress((int)((float)(index-start) * 100 / (float)(limit-start)));
//dialog.setTitle("Disassembling.."+(index-start)+" out of "+(limit-start));
}
mNotifyManager.cancel(0);
final int len=disasmResults.size();
runOnUiThread(new Runnable(){
@Override
public void run()
{
listview.requestLayout();
tab2.invalidate();
Toast.makeText(MainActivity.this, "done", 2).show();
}
});
Log.v(TAG, "disassembly done");
}
});
workerThread.start();
}
Information
The entire source is here, but I think it not needed.
Prototype of cs.disasm:
cs.disasm(bytes,file_offset,virtual_address_to_be_displayed,num_of_instructions_to_be_disassembled);
returns: Array_of_disassembled_info.
The code of cs_disasm(I modified the method to let it support file_offset)
public CsInsn[] disasm(byte[] code,long offset, long length,long address, long count) { PointerByReference insnRef = new PointerByReference(); NativeLong c = cs.cs_disasm2(ns.csh, code,new NativeLong(offset), new NativeLong(length), address, new NativeLong(count), insnRef); if (0 == c.intValue()) { return EMPTY_INSN; } Pointer p = insnRef.getValue(); _cs_insn byref = new _cs_insn(p); CsInsn[] allInsn = fromArrayRaw((_cs_insn[]) byref.toArray(c.intValue())); // free allocated memory // cs.cs_free(p, c); // FIXME(danghvu): Can't free because memory is still inside CsInsn return allInsn; }
Problem
- The
cs.disasm
is called millions of times with file_offset increasing by 4 every loop. - It is a very EXPENSIVE call, as it uses JNA without direct mapping.
What I tried
- Call cs.disasm with last argument 256, and increase file_offset and virtual_address by processed_bytes, which is calculated while processing the returned array.
- Use
final Runnable
so that it doesn't get created every loop.
If you want to see the code I wrote to achieve above, please comment or see edit history. I deleted to make this question more easily readable.
Conditions
- I need to show progress so that users won't get annoyed.
Goal
Is to optimize the above loop.
Just to add, which is faster, calling C from java or calling java from C??
cs.disasm()
call consuming the time? It might as well be therunOnUiThread()
or some other part of your loop. \$\endgroup\$