From bceb82f7339406704d1102b2882a16d9fb7e767b Mon Sep 17 00:00:00 2001 From: emteere <47253321+emteere@users.noreply.github.com> Date: Mon, 29 Jul 2024 17:46:50 -0400 Subject: [PATCH] GP-4742 Added addr='next' to pspec labels. Constrained address spaces for heuristic references --- .../util/opinion/AbstractProgramLoader.java | 16 +- .../program/util/SymbolicPropogator.java | 65 ++++--- .../ConstantPropogationReferenceTest.java | 172 +++++++++++++++++- .../src/decompile/cpp/ghidra_arch.cc | 43 +++-- .../src/decompile/cpp/sleigh_arch.cc | 46 +++-- .../data/languages/processor_spec.rxg | 3 + .../processors/sleigh/SleighLanguage.java | 24 ++- .../program/model/lang/AddressLabelInfo.java | 31 +++- 8 files changed, 319 insertions(+), 81 deletions(-) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/AbstractProgramLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/AbstractProgramLoader.java index da2c57d256..28e214b98a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/AbstractProgramLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/AbstractProgramLoader.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -32,8 +32,7 @@ import ghidra.program.database.ProgramDB; import ghidra.program.database.function.OverlappingFunctionException; import ghidra.program.model.address.*; import ghidra.program.model.lang.*; -import ghidra.program.model.listing.FunctionManager; -import ghidra.program.model.listing.Program; +import ghidra.program.model.listing.*; import ghidra.program.model.mem.InvalidAddressException; import ghidra.program.model.mem.MemoryConflictException; import ghidra.program.model.symbol.*; @@ -487,7 +486,7 @@ public abstract class AbstractProgramLoader implements Loader { for (Register reg : lang.getRegisters()) { Address addr = reg.getAddress(); if (addr.isMemoryAddress()) { - createSymbol(program, reg.getName(), addr, false, true, true); + createSymbol(program, reg.getName(), addr, null, false, true, true); } } // optionally create default symbols defined by pspec @@ -495,7 +494,7 @@ public abstract class AbstractProgramLoader implements Loader { boolean anchorSymbols = shouldAnchorSymbols(options); List labels = lang.getDefaultSymbols(); for (AddressLabelInfo info : labels) { - createSymbol(program, info.getLabel(), info.getAddress(), info.isEntry(), + createSymbol(program, info.getLabel(), info.getAddress(), info.getDescription(), info.isEntry(), info.isPrimary(), anchorSymbols); } } @@ -507,13 +506,16 @@ public abstract class AbstractProgramLoader implements Loader { } private static void createSymbol(Program program, String labelname, Address address, - boolean isEntry, boolean isPrimary, boolean anchorSymbols) { + String comment, boolean isEntry, boolean isPrimary, boolean anchorSymbols) { SymbolTable symTable = program.getSymbolTable(); Address addr = address; Symbol s = symTable.getPrimarySymbol(addr); try { Namespace namespace = program.getGlobalNamespace(); s = symTable.createLabel(addr, labelname, namespace, SourceType.IMPORTED); + if (comment != null) { + program.getListing().setComment(address, CodeUnit.EOL_COMMENT, comment); + } if (isEntry) { symTable.addExternalEntryPoint(addr); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java b/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java index cdb61dbb3c..af804b648f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -145,25 +145,7 @@ public class SymbolicPropogator { this.evaluator = eval; - AddressSpace defaultDataSpace = program.getLanguage().getDefaultDataSpace(); - AddressSpace defaultSpace = program.getLanguage().getDefaultSpace(); - defaultSpacesAreTheSame = defaultSpace.equals(defaultDataSpace); - - AddressSpace defaultAddrSpace = program.getAddressFactory().getDefaultAddressSpace(); - - // Only make reference if other reference or symbol exists - memorySpaces = new ArrayList<>(); - for (AddressSpace space : program.getAddressFactory().getAddressSpaces()) { - if (!space.isLoadedMemorySpace()) { - continue; - } - if (space == defaultAddrSpace) { - memorySpaces.add(0, space); // default space is always at index 0 - } - else { - memorySpaces.add(space); - } - } + initValidAddressSpaces(); // if assuming, make a copy of programContext savedProgramContext = programContext; @@ -206,6 +188,44 @@ public class SymbolicPropogator { return bodyDone; } + /** + * Initialize address spaces to be used for a potential reference with an unknown space. + */ + private void initValidAddressSpaces() { + AddressSpace defaultDataSpace = program.getLanguage().getDefaultDataSpace(); + AddressSpace defaultSpace = program.getLanguage().getDefaultSpace(); + defaultSpacesAreTheSame = defaultSpace.equals(defaultDataSpace); + + AddressSpace defaultAddrSpace = program.getAddressFactory().getDefaultAddressSpace(); + + // Only make reference if other reference or symbol exists + memorySpaces = new ArrayList<>(); + for (AddressSpace space : program.getAddressFactory().getAddressSpaces()) { + if (!space.isLoadedMemorySpace()) { + continue; + } + + // only default or defaultData based overlay spaces added + if (space.isOverlaySpace()) { + OverlayAddressSpace ovSpace = (OverlayAddressSpace) space; + AddressSpace baseSpace = ovSpace.getPhysicalSpace(); + if (!( baseSpace.equals(defaultDataSpace) || baseSpace.equals(defaultSpace) ) ) { + continue; + } + } + else if (!( space.equals(defaultDataSpace) || space.equals(defaultSpace) ) ) { + continue; + } + + if (space.equals(defaultAddrSpace)) { + memorySpaces.add(0, space); // default space is always at index 0 + } + else { + memorySpaces.add(space); + } + } + } + /** * Save off the current context and set the current context to a copy * This is done so that the values in the context are not changed, but can be used for computation. @@ -2307,7 +2327,8 @@ public class SymbolicPropogator { AddressSpace instrSpace = instruction.getMinAddress().getAddressSpace(); // Find likely preferred target space - // 1. only non-overlay space is default space, or + // 1. only non-overlay spaces are defaultSpace of defaultDataSpace, + // or overlay spaces with base space of defaultSpace or defaultDataSpace // 2. presence of destination symbol/reference at only one of many possible targets // if this instruction is in an overlay space overlaying the default space, change the default space diff --git a/Ghidra/Features/Base/src/test/java/ghidra/program/util/ConstantPropogationReferenceTest.java b/Ghidra/Features/Base/src/test/java/ghidra/program/util/ConstantPropogationReferenceTest.java index 97b20b3b87..e551d72f42 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/program/util/ConstantPropogationReferenceTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/program/util/ConstantPropogationReferenceTest.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -24,16 +24,19 @@ import org.junit.Test; import generic.test.AbstractGenericTest; import ghidra.app.plugin.core.analysis.ConstantPropagationAnalyzer; import ghidra.app.plugin.core.analysis.ConstantPropagationContextEvaluator; +import ghidra.framework.store.LockException; import ghidra.program.database.ProgramBuilder; -import ghidra.program.model.address.Address; -import ghidra.program.model.address.AddressSet; +import ghidra.program.model.address.*; import ghidra.program.model.lang.Register; import ghidra.program.model.lang.RegisterValue; import ghidra.program.model.listing.*; +import ghidra.program.model.mem.MemoryBlock; +import ghidra.program.model.mem.MemoryConflictException; import ghidra.program.model.pcode.Varnode; import ghidra.program.model.symbol.Reference; import ghidra.program.model.symbol.ReferenceIterator; import ghidra.program.util.SymbolicPropogator.Value; +import ghidra.util.exception.CancelledException; import ghidra.util.exception.NotFoundException; import ghidra.util.task.TaskMonitor; @@ -307,6 +310,167 @@ public class ConstantPropogationReferenceTest extends AbstractGenericTest { assertOperandReferenceTo(1, instr, addr("0x00040100")); } + @Test + public void testOverlayReferences_AARCH64() throws Exception { + + builder = new ProgramBuilder("thunk", ProgramBuilder._AARCH64); + + // Copy and use PasteCopiedListingsBytesScript + // 00400000 fd 7b bf a9 stp x29,x30,[sp, #local_10]! + // 00400004 fd 03 00 91 mov x29,sp + // 00400008 60 00 00 d0 adrp x0,0x40e000 + // 0040000c 01 00 24 91 add x1,x0,#0x900 + // 00400010 60 00 00 d0 adrp x0,0x40e000 + // 00400014 00 40 24 91 add x0=>data:DWORD_0040e910,x0,#0x910 + // 00400018 e2 03 01 aa mov x2=>data:DWORD_0040e900,x1 + // 0040001c e1 15 80 52 mov w1,#0xaf + // 00400020 05 00 00 94 bl FUN_00400034 + // 00400024 21 00 80 d2 mov x1,#0x1 + // 00400028 40 00 80 d2 mov x0,#0x2 + // 0040002c 02 00 00 94 bl FUN_00400034 + // 00400030 c0 03 5f d6 ret + // + // 00400034 c0 03 5f d6 ret + // 00400038 00 00 00 00 ddw 0h + // 0040003c 00 00 00 00 ddw 0h + // + // 0040e900 53 74 72 69 ddw 53747269h + // 0040e904 6e 67 50 61 ddw 6E675061h + // 0040e908 72 61 6d 31 ddw 72616D31h + // 0040e90c 00 00 00 00 ddw 0h + // + // 0040e910 53 74 72 69 ddw 53747269h + // 0040e914 6e 67 50 61 ddw 6E675061h + // 0040e918 72 61 6d 32 ddw 72616D32h + // 0040e91c 00 00 00 00 ddw 0h + + String ovBlockName = "textov"; + + MemoryBlock textBlock = builder.createOverlayMemory(ovBlockName,"0x400000",0x10000); + + builder.setBytes(textBlock.getStart().toString(), + "fd 7b bf a9 fd 03 00 91 60 00 00 d0 01 00 24 91 60 00 00 d0 00 40 24 91 e2 03 01 aa e1 15 80 52 05 00 00 94 21 00 80 d2 40 00 80 d2 02 00 00 94 c0 03 5f d6 c0 03 5f d6"); + + builder.setBytes(ovBlockName+":"+"0x0040e900", + "53 74 72 69 6e 67 50 61 72 61 6d 31 00 00 00 00 53 74 72 69 6e 67 50 61 72 61 6d 32 00 00 00 00"); + + builder.disassemble(textBlock.getStart().toString(), 16*4); + + analyzer = new ConstantPropagationAnalyzer(); + + program = builder.getProgram(); + program.startTransaction("Test"); + Address codeStart = addr(ovBlockName+":"+"0x00400000"); + Listing listing = program.getListing(); + assertNotNull("Bad instruction disassembly", listing.getInstructionAt(codeStart)); + + AddressSet addressSet = new AddressSet(codeStart, codeStart.add(16*4)); + analyze(addressSet); + + Instruction instr; + instr = listing.getInstructionAt(addr(ovBlockName+":"+"0x00400000").add(20)); + assertNoOperandReference(1, instr); + assertOperandReferenceTo(0, instr, addr(ovBlockName+":"+"0x0040e910")); + + instr = listing.getInstructionAt(addr(ovBlockName+":"+"0x00400000").add(24)); + assertNoOperandReference(1, instr); + assertOperandReferenceTo(0, instr, addr(ovBlockName+":"+"0x0040e900")); + } + + @Test + public void testOverlayReferencesToBase_AARCH64() throws Exception { + + builder = new ProgramBuilder("thunk", ProgramBuilder._AARCH64); + + String ovBlockName = "textov"; + + // Same as above test + + MemoryBlock textBlock = builder.createOverlayMemory(ovBlockName,"0x400000",0x1000); + + builder.setBytes(textBlock.getStart().toString(), + "fd 7b bf a9 fd 03 00 91 60 00 00 d0 01 00 24 91 60 00 00 d0 00 40 24 91 e2 03 01 aa e1 15 80 52 05 00 00 94 21 00 80 d2 40 00 80 d2 02 00 00 94 c0 03 5f d6 c0 03 5f d6"); + + builder.setBytes("0x0040e900", + "53 74 72 69 6e 67 50 61 72 61 6d 31 00 00 00 00 53 74 72 69 6e 67 50 61 72 61 6d 32 00 00 00 00"); + + builder.disassemble(textBlock.getStart().toString(), 16*4); + + analyzer = new ConstantPropagationAnalyzer(); + + program = builder.getProgram(); + program.startTransaction("Test"); + Address codeStart = addr(ovBlockName+":"+"0x00400000"); + Listing listing = program.getListing(); + assertNotNull("Bad instruction disassembly", listing.getInstructionAt(codeStart)); + + AddressSet addressSet = new AddressSet(codeStart, codeStart.add(16*4)); + analyze(addressSet); + + Instruction instr; + instr = listing.getInstructionAt(addr(ovBlockName+":"+"0x00400000").add(20)); + assertNoOperandReference(1, instr); + assertOperandReferenceTo(0, instr, addr("0x0040e910")); + + instr = listing.getInstructionAt(addr(ovBlockName+":"+"0x00400000").add(24)); + assertNoOperandReference(1, instr); + assertOperandReferenceTo(0, instr, addr("0x0040e900")); + } + + + @Test + public void testOverlayReferencesToSplit_AARCH64() throws Exception { + + builder = new ProgramBuilder("thunk", ProgramBuilder._AARCH64); + + String ovBlockName = "textov"; + + // Same as above test + + MemoryBlock textBlock = builder.createOverlayMemory(ovBlockName,"0x400000",0x1000); + + builder.setBytes(textBlock.getStart().toString(), + "fd 7b bf a9 fd 03 00 91 60 00 00 d0 01 00 24 91 60 00 00 d0 00 40 24 91 e2 03 01 aa e1 15 80 52 05 00 00 94 21 00 80 d2 40 00 80 d2 02 00 00 94 c0 03 5f d6 c0 03 5f d6"); + + + builder.withTransaction(() -> { + try { + MemoryBlock dataBlock = builder.getProgram().getMemory().createInitializedBlock(ovBlockName, textBlock.getStart().getAddressSpace().getAddressInThisSpaceOnly(0x0040e900), 0x100L, (byte) 0, TaskMonitor.DUMMY, + false); + + builder.setBytes(dataBlock.getStart().toString(), + "53 74 72 69 6e 67 50 61 72 61 6d 31 00 00 00 00 53 74 72 69 6e 67 50 61 72 61 6d 32 00 00 00 00"); + } + catch (Exception e) { + e.printStackTrace(); + } + }); + + builder.disassemble(textBlock.getStart().toString(), 16*4); + + analyzer = new ConstantPropagationAnalyzer(); + + program = builder.getProgram(); + program.startTransaction("Test"); + Address codeStart = addr(ovBlockName+":"+"0x00400000"); + Listing listing = program.getListing(); + assertNotNull("Bad instruction disassembly", listing.getInstructionAt(codeStart)); + + AddressSet addressSet = new AddressSet(codeStart, codeStart.add(16*4)); + analyze(addressSet); + + Instruction instr; + instr = listing.getInstructionAt(addr(ovBlockName+":"+"0x00400000").add(20)); + assertNoOperandReference(1, instr); + assertOperandReferenceTo(0, instr, addr(ovBlockName+":"+"0x0040e910")); + + instr = listing.getInstructionAt(addr(ovBlockName+":"+"0x00400000").add(24)); + assertNoOperandReference(1, instr); + assertOperandReferenceTo(0, instr, addr(ovBlockName+":"+"0x0040e900")); + } + + + @Test public void testPIC_Call_X86_64() throws Exception { diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.cc index 560c6708fe..34226889c3 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.cc @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -384,28 +384,30 @@ void ArchitectureGhidra::buildSymbols(DocumentStorage &store) { const Element *symtag = store.getTag(ELEM_DEFAULT_SYMBOLS.getName()); - if (symtag == (const Element *)0) return; - XmlDecode decoder(this,symtag); + if (symtag == (const Element*) 0) + return; + XmlDecode decoder(this, symtag); uint4 el = decoder.openElement(ELEM_DEFAULT_SYMBOLS); - while(decoder.peekElement() != 0) { + Address lastAddr(Address::m_minimal); + int4 lastSize = -1; + while (decoder.peekElement() != 0) { uint4 subel = decoder.openElement(ELEM_SYMBOL); string addrString; string name; int4 size = 0; int4 volatileState = -1; - for(;;) { + for (;;) { uint4 attribId = decoder.getNextAttributeId(); - if (attribId == 0) break; + if (attribId == 0) + break; if (attribId == ATTRIB_NAME) - name = decoder.readString(); + name = decoder.readString(); else if (attribId == ATTRIB_ADDRESS) { - addrString = decoder.readString(); - } - else if (attribId == ATTRIB_VOLATILE) { - volatileState = decoder.readBool() ? 1 : 0; - } - else if (attribId == ATTRIB_SIZE) - size = decoder.readSignedInteger(); + addrString = decoder.readString(); + } else if (attribId == ATTRIB_VOLATILE) { + volatileState = decoder.readBool() ? 1 : 0; + } else if (attribId == ATTRIB_SIZE) + size = decoder.readSignedInteger(); } decoder.closeElement(subel); if (name.size() == 0) @@ -417,14 +419,21 @@ void ArchitectureGhidra::buildSymbols(DocumentStorage &store) // feed the global symbol to the decompiler on a per function basic. if (volatileState < 0) continue; - Address addr = parseAddressSimple(addrString); + Address addr; + if (addrString == "next" && lastSize != -1) { + addr = lastAddr + lastSize; + } else { + addr = parseAddressSimple(addrString); + } if (size == 0) size = addr.getSpace()->getWordSize(); - Range range(addr.getSpace(),addr.getOffset(),addr.getOffset() + (size-1)); + Range range(addr.getSpace(), addr.getOffset(), addr.getOffset() + (size - 1)); if (volatileState == 0) symboltab->clearPropertyRange(Varnode::volatil, range); else symboltab->setPropertyRange(Varnode::volatil, range); + lastAddr = addr; + lastSize = size; } decoder.closeElement(el); } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.cc index b8690157c6..bc6cf65ddd 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.cc @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -267,28 +267,36 @@ void SleighArchitecture::buildSymbols(DocumentStorage &store) { const Element *symtag = store.getTag(ELEM_DEFAULT_SYMBOLS.getName()); - if (symtag == (const Element *)0) return; - XmlDecode decoder(this,symtag); + if (symtag == (const Element*) 0) + return; + XmlDecode decoder(this, symtag); uint4 el = decoder.openElement(ELEM_DEFAULT_SYMBOLS); - while(decoder.peekElement() != 0) { + Address lastAddr(Address::m_minimal); + int4 lastSize = -1; + while (decoder.peekElement() != 0) { uint4 subel = decoder.openElement(ELEM_SYMBOL); Address addr; string name; + string description; int4 size = 0; int4 volatileState = -1; - for(;;) { + for (;;) { uint4 attribId = decoder.getNextAttributeId(); - if (attribId == 0) break; + if (attribId == 0) + break; if (attribId == ATTRIB_NAME) - name = decoder.readString(); + name = decoder.readString(); else if (attribId == ATTRIB_ADDRESS) { - addr = parseAddressSimple(decoder.readString()); - } - else if (attribId == ATTRIB_VOLATILE) { - volatileState = decoder.readBool() ? 1 : 0; - } - else if (attribId == ATTRIB_SIZE) - size = decoder.readSignedInteger(); + string addrStr = decoder.readString(); + if (addrStr == "next" && lastSize != -1) { + addr = lastAddr + lastSize; + } else { + addr = parseAddressSimple(addrStr); + } + } else if (attribId == ATTRIB_VOLATILE) { + volatileState = decoder.readBool() ? 1 : 0; + } else if (attribId == ATTRIB_SIZE) + size = decoder.readSignedInteger(); } decoder.closeElement(subel); if (name.size() == 0) @@ -298,15 +306,17 @@ void SleighArchitecture::buildSymbols(DocumentStorage &store) if (size == 0) size = addr.getSpace()->getWordSize(); if (volatileState >= 0) { - Range range(addr.getSpace(),addr.getOffset(),addr.getOffset() + (size-1)); + Range range(addr.getSpace(), addr.getOffset(), addr.getOffset() + (size - 1)); if (volatileState == 0) - symboltab->clearPropertyRange(Varnode::volatil, range); + symboltab->clearPropertyRange(Varnode::volatil, range); else - symboltab->setPropertyRange(Varnode::volatil, range); + symboltab->setPropertyRange(Varnode::volatil, range); } Datatype *ct = types->getBase(size, TYPE_UNKNOWN); Address usepoint; symboltab->getGlobalScope()->addSymbol(name, ct, addr, usepoint); + lastAddr = addr; + lastSize = size; } decoder.closeElement(el); } diff --git a/Ghidra/Framework/SoftwareModeling/data/languages/processor_spec.rxg b/Ghidra/Framework/SoftwareModeling/data/languages/processor_spec.rxg index 03b3ef8704..b3e4f25b8b 100644 --- a/Ghidra/Framework/SoftwareModeling/data/languages/processor_spec.rxg +++ b/Ghidra/Framework/SoftwareModeling/data/languages/processor_spec.rxg @@ -146,6 +146,9 @@ + + + diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighLanguage.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighLanguage.java index 9d777e90b1..9c68b72f09 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighLanguage.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighLanguage.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -756,14 +756,28 @@ public class SleighLanguage implements Language { } else if (elName.equals("default_symbols")) { XmlElement subel = parser.start(); + Address previousAddr = null; + int previousSize = 1; while (parser.peek().getName().equals("symbol")) { XmlElement symbol = parser.start(); String labelName = symbol.getAttribute("name"); String addressString = symbol.getAttribute("address"); String typeString = symbol.getAttribute("type"); + String comment = symbol.getAttribute("description"); ProcessorSymbolType type = ProcessorSymbolType.getType(typeString); boolean isEntry = SpecXmlUtils.decodeBoolean(symbol.getAttribute("entry")); - Address startAddress = addressFactory.getAddress(addressString); + Address startAddress = null; + if (addressString.equalsIgnoreCase("next")) { + if (previousAddr == null) { + Msg.error(this, "use of addr=\"next\" tag with no previous address for " + + labelName + " : " + description.getSpecFile()); + } else { + startAddress = previousAddr.add(previousSize); + } + } + else { + startAddress = addressFactory.getAddress(addressString); + } int rangeSize = SpecXmlUtils.decodeInt(symbol.getAttribute("size")); Boolean isVolatile = SpecXmlUtils.decodeNullableBoolean(symbol.getAttribute("volatile")); @@ -774,7 +788,7 @@ public class SleighLanguage implements Language { else { AddressLabelInfo info; try { - info = new AddressLabelInfo(startAddress, rangeSize, labelName, false, + info = new AddressLabelInfo(startAddress, rangeSize, labelName, comment, false, isEntry, type, isVolatile); } catch (AddressOverflowException e) { @@ -801,6 +815,8 @@ public class SleighLanguage implements Language { } // skip the end tag parser.end(symbol); + previousAddr = startAddress; + previousSize = rangeSize; } parser.end(subel); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/AddressLabelInfo.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/AddressLabelInfo.java index d85e85ddcb..ef114b9018 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/AddressLabelInfo.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/AddressLabelInfo.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -29,6 +29,7 @@ public class AddressLabelInfo implements Comparable { private Address addr; private Address endAddr; private String label; + private String description; private boolean isPrimary; private boolean isEntry; private ProcessorSymbolType processorSymbolType; @@ -41,12 +42,13 @@ public class AddressLabelInfo implements Comparable { * @param addr Address object that describes the memory address * @param sizeInBytes Integer describing the Size in bytes that the label applies to. * @param label String label or alias for the Address + * @param description Label description * @param isPrimary boolean describes if this object is the primary label for the Address 'addr' * @param isEntry boolean describes if this object is an entry label for the Address 'addr' * @param type ProcessorSymbolType the type of symbol * @param isVolatile Boolean describes if the memory at this address is volatile */ - public AddressLabelInfo(Address addr, Integer sizeInBytes, String label, boolean isPrimary, + public AddressLabelInfo(Address addr, Integer sizeInBytes, String label, String description, boolean isPrimary, boolean isEntry, ProcessorSymbolType type, Boolean isVolatile) throws AddressOverflowException { this.addr = addr; if ( sizeInBytes == null || sizeInBytes <= 0 ) { @@ -57,6 +59,7 @@ public class AddressLabelInfo implements Comparable { } this.endAddr = this.addr.addNoWrap(this.sizeInBytes-1); this.label = label; + this.description = description; this.isPrimary = isPrimary; this.isEntry = isEntry; this.processorSymbolType = type; @@ -64,28 +67,35 @@ public class AddressLabelInfo implements Comparable { } /** - * Returns the object's address. + * @return object's address. */ public final Address getAddress() { return addr; } /** - * Returns the object's end address. + * @return the object's end address. */ public final Address getEndAddress() { return endAddr; } /** - * Returns the object's label or alias. + * @return the object's label or alias. */ public final String getLabel() { return label; } + + /** + * @return the object's description if it has one, null otherwise + */ + public final String getDescription() { + return description; + } /** - * Returns the object's size in bytes. Always non-zero positive value and defaults to + * @return the object's size in bytes. Always non-zero positive value and defaults to * addressable unit size of associated address space. */ public final int getByteSize() { @@ -93,14 +103,14 @@ public class AddressLabelInfo implements Comparable { } /** - * Returns whether the object is the primary label at the address. + * @return whether the object is the primary label at the address. */ public final boolean isPrimary() { return isPrimary; } /** - * Returns whether the object is volatile. + * @return whether the object is volatile. * Boolean.False when the address is explicitly not volatile. * Boolean.True when the address is volatile. * NULL when the volatility is not defined at this address. @@ -164,6 +174,9 @@ public class AddressLabelInfo implements Comparable { buf.append("isEntry = " + isEntry); buf.append(", "); buf.append("type = " + processorSymbolType); + if (description != null) { + buf.append("description = " + description); + } return buf.toString(); } }