Merge branch 'GP-0_ryanmkurtz_PR-9427_mi11ione_fix-lsda-ttype-base'

This commit is contained in:
Ryan Kurtz
2026-07-30 05:30:17 -04:00
4 changed files with 195 additions and 5 deletions

View File

@@ -150,8 +150,8 @@ public class LSDAHeader extends GccAnalysisClass {
LEB128Info uleb128 = GccAnalysisUtils.readULEB128Info(program, addr);
// this offset it based from *here*..
ttypeOffset = uleb128.asLong() + curSize;
// this offset is based from the end of *this* field, and the base is the table's last byte
ttypeOffset = uleb128.asLong() + curSize + uleb128.getLength() - 1;
createAndCommentData(program, addr, UnsignedLeb128DataType.dataType, comment,
CommentType.EOL);
@@ -306,7 +306,7 @@ public class LSDAHeader extends GccAnalysisClass {
}
/**
* The offset from the type offset field to get to the base address of the type table.
* The offset from the start of the LSDA to the base address of the type table.
* @return the type table offset
*/
public int getTTypeOffset() {

View File

@@ -20,7 +20,7 @@ import java.util.List;
import ghidra.app.cmd.comments.SetCommentCmd;
import ghidra.app.plugin.exceptionhandlers.gcc.*;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.*;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.CommentType;
import ghidra.program.model.listing.Program;
@@ -100,7 +100,8 @@ public class LSDATypeTable extends GccAnalysisClass {
}
}
catch (MemoryAccessException mae) {
catch (MemoryAccessException | AddressOutOfBoundsException e) {
// a pc-relative entry landing outside the address space throws the unchecked one
SetCommentCmd commentCmd =
new SetCommentCmd(addr, CommentType.EOL, "Unable to resolve pointer");
commentCmd.applyTo(program);

View File

@@ -0,0 +1,113 @@
/* ###
* IP: GHIDRA
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.plugin.exceptionhandlers.gcc.structures.gccexcepttable;
import static org.junit.Assert.*;
import org.junit.*;
import generic.test.AbstractGenericTest;
import ghidra.app.plugin.exceptionhandlers.gcc.RegionDescriptor;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.Program;
import ghidra.util.task.TaskMonitor;
/**
* Tests that the LSDA header locates the type table correctly however many bytes the TType
* offset ULEB128 occupies. Each LSDA below runs LPStart encoding (omitted), TType encoding
* (pcrel|sdata4), TType offset, call site encoding (uleb128) and table length, call site
* records, action table, then a single type table entry ending at the type table base.
*/
public class LSDAHeaderTest extends AbstractGenericTest {
private ProgramBuilder builder;
private Program program;
@Before
public void setUp() throws Exception {
builder = new ProgramBuilder("lsda", ProgramBuilder._X64);
builder.createMemory("lsda", "0x1000", 0x400);
program = builder.getProgram();
}
@After
public void tearDown() {
builder.dispose();
}
@Test
public void testSingleByteTTypeOffset() throws Exception {
builder.setBytes("0x1000", "ff 1b 0d 01 04 00 02 02 01 01 00 00 f4 02 00 00");
LSDATable table = createTable();
assertEquals(addr(0x100f), table.getHeader().getTTypeBaseAddress());
assertEquals(addr(0x1300), table.getTypeTable().getTypeInfoAddress(1));
}
@Test
public void testTwoByteTTypeOffset() throws Exception {
builder.setBytes("0x1000",
"ff 1b 80 01 01 78 " + "00 02 02 01 ".repeat(30) + "01 00 80 02 00 00");
LSDATable table = createTable();
assertEquals(addr(0x1083), table.getHeader().getTTypeBaseAddress());
assertEquals(addr(0x1300), table.getTypeTable().getTypeInfoAddress(1));
}
@Test
public void testThreeByteTTypeOffset() throws Exception {
builder.setBytes("0x1000", "ff 1b 80 80 01 01 00");
LSDAHeader header = new LSDAHeader(TaskMonitor.DUMMY, program, region());
int id = program.startTransaction("lsda");
try {
header.create(addr(0x1000));
}
finally {
program.endTransaction(id, true);
}
assertEquals(addr(0x5004), header.getTTypeBaseAddress());
}
private LSDATable createTable() throws Exception {
RegionDescriptor region = region();
region.setLSDAAddress(addr(0x1000));
int id = program.startTransaction("lsda");
try {
LSDATable table = new LSDATable(TaskMonitor.DUMMY, program);
table.create(addr(0x1000), region);
return table;
}
finally {
program.endTransaction(id, true);
}
}
private RegionDescriptor region() {
RegionDescriptor region = new RegionDescriptor(program.getMemory().getBlock(addr(0x1000)));
region.setIPRange(new AddressRangeImpl(addr(0x1000), addr(0x1100)));
return region;
}
private Address addr(long offset) {
return program.getAddressFactory().getDefaultAddressSpace().getAddress(offset);
}
}

View File

@@ -0,0 +1,76 @@
/* ###
* IP: GHIDRA
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.plugin.exceptionhandlers.gcc.structures.gccexcepttable;
import static org.junit.Assert.*;
import org.junit.*;
import generic.test.AbstractGenericTest;
import ghidra.app.plugin.exceptionhandlers.gcc.RegionDescriptor;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.Program;
import ghidra.util.task.TaskMonitor;
/**
* Tests that an entry the type table cannot resolve costs only that entry. The type table is
* built last, so an exception escaping it would discard the call site and action tables that
* {@link LSDATable#create} has already finished.
*/
public class LSDATypeTableTest extends AbstractGenericTest {
private ProgramBuilder builder;
private Program program;
@Before
public void setUp() throws Exception {
builder = new ProgramBuilder("lsda", ProgramBuilder._X64);
builder.createMemory("lsda", "0x1000", 0x400);
program = builder.getProgram();
}
@After
public void tearDown() {
builder.dispose();
}
@Test
public void testUnresolvableTypeEntryKeepsCallSiteTable() throws Exception {
// the sole type table entry is a pc-relative displacement that leaves the address space
builder.setBytes("0x1000", "ff 1b 0d 01 04 00 02 02 01 01 00 00 01 00 00 80");
Address lsda = addr(0x1000);
RegionDescriptor region = new RegionDescriptor(program.getMemory().getBlock(lsda));
region.setIPRange(new AddressRangeImpl(lsda, addr(0x1100)));
region.setLSDAAddress(lsda);
LSDATable table = new LSDATable(TaskMonitor.DUMMY, program);
int id = program.startTransaction("lsda");
try {
table.create(lsda, region);
}
finally {
program.endTransaction(id, true);
}
assertEquals(1, table.getCallSiteTable().getCallSiteRecords().size());
}
private Address addr(long offset) {
return program.getAddressFactory().getDefaultAddressSpace().getAddress(offset);
}
}