ghidra icon indicating copy to clipboard operation
ghidra copied to clipboard

Joining blocks has different behavior than the gui Merge button

Open Decryptortuning opened this issue 1 year ago • 2 comments

The error: "ghidra.program.model.mem.MemoryBlockException: Blocks are not contiguous" appears when I am trying to join some blocks together using a Py2.7/Jython based script. HOWEVER, when I use the GUI "Merge blocks" button it works just fine.

My script is using the ghidra API method "join" from the Class MemoryMapDB. This tracks back to line 1050 in MemoryMapDB.java "public MemoryBlock join".

Ghidra's GUI "MERGE" button tracks back to MemoryMapManager.java @ line 66 "void mergeBlocks"

What strikes me is the massive difference in the way these perform the same task. Every time I try to "join" blocks, I get this "Blocks are not contiguous" error. I can then go and click those two same blocks and hit "Merge" and get the desired / proper behavior. This also means that the test for block continuity is different. "private boolean goodBlocks" does the testing for the gui and it works just fine. The 'join' uses "private void checkPreconditionsForJoining" to do the "same" testing. At least it seems that way to the end user but behind the scenes its rather different.

Is it possible to use the mergeBlocks function via script somehow? This would be acceptable.

A snippet of my script where I use the Join...

 #Check if there's an overlap
                if (block_start.compareTo(end_address) <= 0) and (block_end.compareTo(start_address) >= 0):
                    logging.info("Overlap found with block: %s" % block.getName())
                    if not merged:
                        logging.info("Renaming block: %s to %s" % (block.getName(), block_name))
                        block.setName(block_name)
                        merged = True
                    else:
                        logging.info("Merging block: %s with previous block: %s" % (block.getName(), previous_block.getName()))
                        memoryMap.join(previous_block, block)
                    previous_block = block
                elif merged:
                    logging.info("Joining block: %s with merged previous block: %s" % (block.getName(), previous_block.getName()))
                    memoryMap.join(previous_block, block)

            if not merged:
                # If no blocks were merged, create a new one
                logging.info("No blocks merged. Creating new block: %s" % block_name)
                memoryMap.createInitializedBlock(block_name, start_address, end_address.subtract(start_address).getOffset() + 1, False)

To Reproduce Steps to reproduce the behavior:

  1. Load the attached Tricore based hex file for similar segmentation provided by the initial hex file loading.
  2. use "join" to merge the first two blocks via a python script, error should happen here.

Expected behavior I expect the blocks to join instead of not.

Attachments ESA_HEX_noheader.zip This is my hex file that creates the original segments that I am trying to then join. I am willing to provide my entire Script privately to devs so you can reproduce this error quickly. I just cant post it here directly. Environment:

  • OS: WIn10 current build
  • Java Version: 17+
  • Ghidra Version: 11
  • Ghidra Origin: Github

Decryptortuning avatar Dec 30 '23 00:12 Decryptortuning

@Decryptortuning I have code that is doing similar, haven't messed with it in a while, but maybe useful as another reference.
https://github.com/mumbel/MufomReader/blob/main/src/main/java/mufom/MufomLoader.java#L188

I think merge here means... take a start address of a section, and an end address of the next and make them one. the filler is added by this action. join implies to me block1 end is greater than or equal to the start of block2 (i.e. there are no missing addresses). Your tricore's first two sections have 0x10000 bytes not accounted for between them

mumbel avatar Dec 31 '23 19:12 mumbel

Thats a good thought. I may do some auto filler AFAFAF data or something as a test. IE, if gap, fill with AF then join. Sure would be nice to just have merge exposed and usable though. @mumbel do you have any method of contact off of github?

Decryptortuning avatar Jan 01 '24 19:01 Decryptortuning

If you look at the javadoc on join, its behavior is well defined: https://github.com/NationalSecurityAgency/ghidra/blob/7765e8338bb9f866ce31ba98059243f0af2ca80d/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/Memory.java#L502-L513

So, I don't see a problem here...the API is behaving as intended. You simply have to add your own connector block before calling join.

ryanmkurtz avatar Jan 02 '24 13:01 ryanmkurtz