Skip to content

Commit a1697ce

Browse files
committed
ghidra: fix invalid address expection and handle partial union
1 parent 1adac05 commit a1697ce

File tree

2 files changed

+70
-16
lines changed

2 files changed

+70
-16
lines changed

lib/patchestry/Ghidra/JsonDeserialize.cpp

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ namespace patchestry::ghidra {
199199
auto size = static_cast< uint32_t >(type_obj.getInteger("size").value_or(0));
200200
auto kind_str = get_string(type_obj, "kind");
201201
LOG(INFO) << "Attempting to convert kind string: [" << kind_str << "]" << "\n";
202-
auto kind = VarnodeType::convertToKind(kind_str);
202+
auto kind = VarnodeType::convertToKind(kind_str);
203203
switch (kind) {
204204
case VarnodeType::Kind::VT_INVALID: {
205205
LOG(ERROR) << "Invalid varnode type: " << name << "\n";
@@ -324,40 +324,56 @@ namespace patchestry::ghidra {
324324
}
325325

326326
// Iterate through the fields and initialize them
327+
unsigned field_index = 0;
327328
for (const auto &field : *field_array) {
328329
const auto *field_obj = field.getAsObject();
329330
if (field_obj == nullptr) {
330-
LOG(ERROR) << "Skipping invalid field object.\n";
331+
LOG(ERROR) << "Field #" << field_index
332+
<< ": Invalid field object format, skipping\n";
333+
++field_index;
331334
continue;
332335
}
333336

334337
auto field_type_key = get_string_if_valid(*field_obj, "type");
335338
if (!field_type_key) {
336-
LOG(ERROR) << "Skipping field: missing type\n";
339+
LOG(ERROR) << "Field #" << field_index
340+
<< ": Missing required 'type' attribute, skipping\n";
341+
++field_index;
337342
continue;
338343
}
339344

340345
auto iter = serialized_types.find(*field_type_key);
341346
if (iter == serialized_types.end()) {
342-
LOG(ERROR) << "Skipping field: component is not found on serialized types.\n";
347+
LOG(ERROR) << "Field #" << field_index << ": Type '" << *field_type_key
348+
<< "' not found in serialized types registry, skipping\n";
349+
++field_index;
343350
continue;
344351
}
345352

346353
auto maybe_offset = field_obj->getInteger("offset");
347354
if (!maybe_offset) {
348-
LOG(ERROR) << "Skipping field: invalid offset value.\n";
355+
LOG(ERROR) << "Field #" << field_index
356+
<< ": Missing or invalid 'offset' value, skipping\n";
357+
++field_index;
349358
continue;
350359
}
351360

361+
std::string field_name;
352362
auto maybe_name = get_string_if_valid(*field_obj, "name");
353-
if (!maybe_name) {
354-
LOG(ERROR) << "Skipping field: invalid name.\n";
355-
continue;
363+
if (maybe_name) {
364+
field_name = *maybe_name;
365+
} else {
366+
field_name = "field_" + std::to_string(field_index);
367+
LOG(WARNING) << "Field #" << field_index
368+
<< " Missing or invalid name, using default: '" << field_name
369+
<< "'\n";
356370
}
357371

358372
varnode.add_components(
359-
*maybe_name, *iter->second, static_cast< uint32_t >(*maybe_offset)
373+
field_name, *iter->second, static_cast< uint32_t >(*maybe_offset)
360374
);
375+
376+
++field_index;
361377
}
362378
}
363379

scripts/ghidra/PatchestryDecompileFunctions.java

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import ghidra.program.model.address.AddressSet;
2828
import ghidra.program.model.address.AddressSetView;
2929
import ghidra.program.model.address.AddressSpace;
30+
import ghidra.program.model.address.AddressOutOfBoundsException;
3031

3132
import ghidra.program.model.block.BasicBlockModel;
3233
import ghidra.program.model.block.CodeBlock;
@@ -576,9 +577,13 @@ private void serialize(DataType data_type) throws Exception {
576577
serializePrototype((FunctionSignature) data_type);
577578

578579
} else if (data_type instanceof PartialUnion) {
579-
name("kind").value("todo:PartialUnion"); // TODO(pag): Implement this
580-
name("size").value(data_type.getLength());
581-
580+
DataType parent = ((PartialUnion) data_type).getParent();
581+
if (parent != data_type) {
582+
serialize(parent);
583+
} else {
584+
// PartialUnion stripped type is undefined type
585+
serialize(((PartialUnion) data_type).getStrippedDataType());
586+
}
582587
} else if (data_type instanceof BitFieldDataType) {
583588
name("kind").value("todo:BitFieldDataType"); // TODO(pag): Implement this
584589
name("size").value(data_type.getLength());
@@ -846,7 +851,20 @@ private Address convertAddressToRamSpace(Address address) throws Exception {
846851
if (address == null) {
847852
return null;
848853
}
849-
return ram_space.getAddress(address.toString(false));
854+
855+
try {
856+
// If already in RAM space, just return it
857+
if (address.getAddressSpace().getName().equals("ram")) {
858+
return address;
859+
}
860+
861+
// Get the numeric offset and create a new address in RAM space
862+
long offset = address.getOffset();
863+
return program.getAddressFactory().getDefaultAddressSpace().getAddress(offset);
864+
} catch (Exception e) {
865+
println(String.format("Failed to convert address %s to RAM space: %s", address, e.getMessage()));
866+
return null;
867+
}
850868
}
851869

852870
private boolean isCharPointer(Varnode node) throws Exception {
@@ -875,6 +893,9 @@ private String findNullTerminatedString(Address address, Pointer pointer) throws
875893
}
876894

877895
Address ram_address = convertAddressToRamSpace(address);
896+
if (ram_address == null) {
897+
return null;
898+
}
878899
MemoryBufferImpl memoryBuffer = new MemoryBufferImpl(program.getMemory(), ram_address);
879900
DataType char_type = pointer.getDataType();
880901
//println("Debug: char_type = " + char_type.getName() + ", size = " + char_type.getLength());
@@ -891,14 +912,31 @@ private String findNullTerminatedString(Address address, Pointer pointer) throws
891912
}
892913

893914
private Data getDataReferencedAsConstant(Varnode node) throws Exception {
915+
// check if node is null
916+
if (node == null) {
917+
return null;
918+
}
919+
920+
// Only process constant nodes that aren't nulls (address 0 in constant space)
894921
if (!node.isConstant() || node.getAddress().equals(constant_space.getAddress(0))) {
895922
return null;
896923
}
924+
897925
// Ghidra sometime fail to resolve references to Data and show it as const.
898926
// Check if it is referencing Data as constant from `ram` addresspace.
899-
Address ram_address = convertAddressToRamSpace(node.getAddress());
900-
Data data = getDataAt(ram_address);
901-
return data;
927+
try {
928+
// Convert the constant value to a potential RAM address
929+
Address ram_address = convertAddressToRamSpace(node.getAddress());
930+
if (ram_address == null) {
931+
return null;
932+
}
933+
return getDataAt(ram_address);
934+
935+
} catch (AddressOutOfBoundsException e) {
936+
println("Address conversion out of bounds for constant: " + e.getMessage());
937+
}
938+
939+
return null;
902940
}
903941

904942
// Serialize an input or output varnode.

0 commit comments

Comments
 (0)