Merge remote-tracking branch

'origin/GP-6645_dev747368_fix_golang_npe_mac_1_26_firstmoduledata'
(Closes #9093)
This commit is contained in:
Ryan Kurtz
2026-04-03 11:46:02 -04:00
5 changed files with 93 additions and 16 deletions
@@ -302,10 +302,14 @@ public class GolangStringAnalyzer extends AbstractAnalyzer {
throws IOException, CancelledException { throws IOException, CancelledException {
// test to see if its a slice first because strings can kinda look like slices (a pointer // test to see if its a slice first because strings can kinda look like slices (a pointer
// then a length field). // then a length field).
boolean isUndefined3x = boolean isDefPtr = isDefaultPointer(addr);
DataUtilities.isUndefinedRange(program, addr, addr.add(sliceStructLen)); boolean isUndefined3x = (isDefPtr && DataUtilities.isUndefinedRange(program,
addr.add(goBinary.getPtrSize()), addr.add(sliceStructLen - 1))) ||
DataUtilities.isUndefinedRange(program, addr, addr.add(sliceStructLen - 1));
boolean isUndefined2x = isUndefined3x || boolean isUndefined2x = isUndefined3x ||
DataUtilities.isUndefinedRange(program, addr, addr.add(stringStructLen)); (isDefPtr && DataUtilities.isUndefinedRange(program,
addr.add(goBinary.getPtrSize()), addr.add(stringStructLen - 1))) ||
DataUtilities.isUndefinedRange(program, addr, addr.add(stringStructLen - 1));
Object newObj = isUndefined3x ? tryReadSliceStruct(addr) : null; Object newObj = isUndefined3x ? tryReadSliceStruct(addr) : null;
if (newObj == null && isUndefined2x) { if (newObj == null && isUndefined2x) {
@@ -323,6 +327,12 @@ public class GolangStringAnalyzer extends AbstractAnalyzer {
return newObj; return newObj;
} }
private boolean isDefaultPointer(Address addr) {
Data data = program.getListing().getDataAt(addr);
return data != null && data.getDataType() instanceof DataType dt &&
((dt instanceof Pointer ptr && ptr.getDataType() == null) || Undefined.isUndefined(dt));
}
private GoString tryReadStringStruct(AddressSetView stringDataRange, Address addr) { private GoString tryReadStringStruct(AddressSetView stringDataRange, Address addr) {
try { try {
GoString goString = goBinary.readStructure(GoString.class, addr); GoString goString = goBinary.readStructure(GoString.class, addr);
@@ -61,6 +61,18 @@ public class GoParamStorageAllocator {
lang.getLanguageDescription().getSize()); lang.getLanguageDescription().getSize());
} }
public GoParamStorageAllocator(GoRegisterInfo callspecInfo, Program program) {
Language lang = program.getLanguage();
this.callspecInfo = callspecInfo;
this.stackOffset = callspecInfo.getStackInitialOffset();
this.regs = List.of(callspecInfo.getIntRegisters(), callspecInfo.getFloatRegisters());
this.isBigEndian = lang.isBigEndian();
this.archDescription =
"%s_%d".formatted(lang.getLanguageDescription().getProcessor().toString(),
lang.getLanguageDescription().getSize());
}
private GoParamStorageAllocator(List<List<Register>> regs, int[] nextReg, private GoParamStorageAllocator(List<List<Register>> regs, int[] nextReg,
GoRegisterInfo callspecInfo, long stackOffset, boolean isBigEndian, GoRegisterInfo callspecInfo, long stackOffset, boolean isBigEndian,
String archDescription) { String archDescription) {
@@ -414,7 +414,7 @@ public class GoModuledata implements StructureMarkup<GoModuledata> {
*/ */
/* package */ static GoModuledata getFirstModuledata(GoRttiMapper context) throws IOException { /* package */ static GoModuledata getFirstModuledata(GoRttiMapper context) throws IOException {
Program program = context.getProgram(); Program program = context.getProgram();
MemoryBlock memblk = context.getGoSection("go.module"); MemoryBlock memblk = context.getFirstGoSection("go.module", "go_module");
if (memblk != null) { if (memblk != null) {
return context.readStructure(GoModuledata.class, memblk.getStart()); return context.readStructure(GoModuledata.class, memblk.getStart());
} }
@@ -236,8 +236,8 @@ public class GoRttiMapper extends DataTypeMapper implements DataTypeMapperContex
return null; return null;
} }
public static MemoryBlock getFirstGoSection(Program program, String... blockNames) { public static MemoryBlock getFirstGoSection(Program program, String... sectionNames) {
for (String blockToSearch : blockNames) { for (String blockToSearch : sectionNames) {
MemoryBlock memBlock = getGoSection(program, blockToSearch); MemoryBlock memBlock = getGoSection(program, blockToSearch);
if (memBlock != null) { if (memBlock != null) {
return memBlock; return memBlock;
@@ -522,7 +522,7 @@ public class GoRttiMapper extends DataTypeMapper implements DataTypeMapperContex
* {@return new {@link GoParamStorageAllocator} param storage allocator instance} * {@return new {@link GoParamStorageAllocator} param storage allocator instance}
*/ */
public GoParamStorageAllocator newStorageAllocator() { public GoParamStorageAllocator newStorageAllocator() {
GoParamStorageAllocator storageAllocator = new GoParamStorageAllocator(program, goVer); GoParamStorageAllocator storageAllocator = new GoParamStorageAllocator(regInfo, program);
return storageAllocator; return storageAllocator;
} }
@@ -709,7 +709,12 @@ public class GoRttiMapper extends DataTypeMapper implements DataTypeMapperContex
GoFuncDef snapshotFuncdef = GoFuncDef snapshotFuncdef =
apiSnapshot.getFuncdef(symbolName.getStrippedSymbolString()); apiSnapshot.getFuncdef(symbolName.getStrippedSymbolString());
if (snapshotFuncdef != null) { if (snapshotFuncdef != null) {
return createFuncDefFromApiSnapshot(symbolName, recvType, snapshotFuncdef); try {
return createFuncDefFromApiSnapshot(symbolName, recvType, snapshotFuncdef);
}
catch (IOException e) {
// fail, fall thru to catch-all at bottom
}
} }
} }
@@ -1197,4 +1202,8 @@ public class GoRttiMapper extends DataTypeMapper implements DataTypeMapperContex
public MemoryBlock getGoSection(String sectionName) { public MemoryBlock getGoSection(String sectionName) {
return getGoSection(program, sectionName); return getGoSection(program, sectionName);
} }
public MemoryBlock getFirstGoSection(String... sectionNames) {
return getFirstGoSection(program, sectionNames);
}
} }
@@ -53,6 +53,14 @@ public class GoTypeManager {
")" + // group=1 ")" + // group=1
"(.*)" // everything else, group=2 "(.*)" // everything else, group=2
); );
private static final Pattern CHAN_TYPENAME_REGEX = Pattern.compile(
"(<-)?" + // maybe <-
"chan" + // 'chan'
"(<-)?" + // maybe <-
" " + // mandatory ' '
"(.+)" // everything else, group 3
);
//@formatter:on //@formatter:on
static class TypeRec { static class TypeRec {
@@ -194,8 +202,7 @@ public class GoTypeManager {
long gapStart = t1.end; long gapStart = t1.end;
while (t2.start - gapStart > typeStructMinSize) { while (t2.start - gapStart > typeStructMinSize) {
GoType goType = readTypeUnchecked(gapStart); GoType goType = readTypeUnchecked(gapStart);
if (goType == null || if (goType == null) {
!(goType instanceof GoStructType && goType.getSymbolName().isAnonType())) {
gapStart += typeStructAlign; gapStart += typeStructAlign;
continue; continue;
} }
@@ -440,6 +447,9 @@ public class GoTypeManager {
else if (typeName.startsWith("map[")) { // not handled by splitTypeName() else if (typeName.startsWith("map[")) { // not handled by splitTypeName()
result = newTypeRecFromDT(typeName, createSpecializedMapDT(typeName)); result = newTypeRecFromDT(typeName, createSpecializedMapDT(typeName));
} }
else if (CHAN_TYPENAME_REGEX.matcher(typeName) instanceof Matcher m && m.matches()) {
result = newTypeRecFromDT(typeName, createSpecializedChanDT(typeName, m.group(3)));
}
else { else {
GoKind primitiveTypeKind = GoKind.parseTypename(typeName); GoKind primitiveTypeKind = GoKind.parseTypename(typeName);
GoTypeDef typeDef; GoTypeDef typeDef;
@@ -475,6 +485,8 @@ public class GoTypeManager {
return convertStructDef(typeName, struct); return convertStructDef(typeName, struct);
case GoFuncTypeDef func: case GoFuncTypeDef func:
return convertFuncDef(typeName, func); return convertFuncDef(typeName, func);
case GoInterfaceDef iface:
return convertIfaceDef(typeName, iface);
default: default:
throw new IOException("Go unhandled type definition: " + typeDef.toString()); throw new IOException("Go unhandled type definition: " + typeDef.toString());
} }
@@ -512,11 +524,15 @@ public class GoTypeManager {
returnDT = findDataType(func.Results.get(0).DataType); returnDT = findDataType(func.Results.get(0).DataType);
} }
else { else {
List<DataType> paramDataTypes = new ArrayList<>(); List<DataType> returnDataTypes = new ArrayList<>();
for (GoNameTypePair outParam : func.Results) { for (GoNameTypePair outParam : func.Results) {
paramDataTypes.add(findDataType(outParam.DataType)); DataType dt = findDataType(outParam.DataType);
if (dt == null) {
dt = new StructureDataType(cp, ".missing_" + outParam.DataType, 0);
}
returnDataTypes.add(dt);
} }
returnDT = getFuncMultiReturn(paramDataTypes); returnDT = getFuncMultiReturn(returnDataTypes);
} }
funcDef.setArguments(params.toArray(ParameterDefinition[]::new)); funcDef.setArguments(params.toArray(ParameterDefinition[]::new));
@@ -525,6 +541,21 @@ public class GoTypeManager {
return result; return result;
} }
private TypeRec convertIfaceDef(GoSymbolName typeName, GoInterfaceDef iface)
throws IOException {
TypeRec baseIface = findTypeRec("interface {}");
if (baseIface == null) {
throw new IOException("Missing type info for base interface {}");
}
String name = typeName.asString();
if (baseIface.name.equals(name)) {
return baseIface;
}
CategoryPath cp = getCP(typeName);
TypeDef td = new TypedefDataType(cp, name, baseIface.recoveredDT);
return newTypeRecFromDT(name, td);
}
private TypeRec convertBasicDef(GoSymbolName typeName, GoBasicDef basicDef) throws IOException { private TypeRec convertBasicDef(GoSymbolName typeName, GoBasicDef basicDef) throws IOException {
GoKind kind = GoKind.parseTypename(basicDef.DataType); GoKind kind = GoKind.parseTypename(basicDef.DataType);
if (kind == null) { if (kind == null) {
@@ -581,6 +612,7 @@ public class GoTypeManager {
GoNameTypePair field = structDef.Fields.get(i); GoNameTypePair field = structDef.Fields.get(i);
DataType dtcDT = findDataType(field.DataType); DataType dtcDT = findDataType(field.DataType);
if (dtcDT == null) { if (dtcDT == null) {
dtcDT = findDataType(field.DataType);
throw new IOException("Failed to get type for field [%d %s: %s] in %s" throw new IOException("Failed to get type for field [%d %s: %s] in %s"
.formatted(i, field.Name, field.DataType, typeName)); .formatted(i, field.Name, field.DataType, typeName));
} }
@@ -879,6 +911,21 @@ public class GoTypeManager {
return voidPtrDT; return voidPtrDT;
} }
public DataType createSpecializedChanDT(String fullChanTypeName, String elementTypeName) {
try {
Structure hchanStruct = findDataType("runtime.hchan", Structure.class);
if (hchanStruct != null) {
GoSymbolName typeSymbolName = GoSymbolName.parseTypeName(elementTypeName);
return new TypedefDataType(getCP(typeSymbolName), fullChanTypeName,
dtm.getPointer(hchanStruct), dtm);
}
}
catch (IOException e) {
// fall thru
}
return voidPtrDT;
}
/** /**
* {@return data type that represents a generic Go slice} * {@return data type that represents a generic Go slice}
* @throws IOException * @throws IOException
@@ -1076,7 +1123,7 @@ public class GoTypeManager {
} }
throw new IOException("Unknown type prefix: " + name); throw new IOException("Unknown type prefix: " + name);
} }
else if (name.startsWith("map[") || name.startsWith("chan ")) { else if (name.startsWith("map[") || CHAN_TYPENAME_REGEX.matcher(name).matches()) {
return new LengthAlignment(ptrSize, align(ptrSize)); return new LengthAlignment(ptrSize, align(ptrSize));
} }
else { else {
@@ -1112,8 +1159,7 @@ public class GoTypeManager {
return new LengthAlignment(ptrSize * 2, align(ptrSize)); return new LengthAlignment(ptrSize * 2, align(ptrSize));
} }
private LengthAlignment getDataTypeLength(GoStructDef structDef) private LengthAlignment getDataTypeLength(GoStructDef structDef) throws IOException {
throws IOException {
int len = 0; int len = 0;
int align = 1; int align = 1;
for (GoNameTypePair field : structDef.Fields) { for (GoNameTypePair field : structDef.Fields) {