Merge remote-tracking branch 'origin/GP-49_external_disassembly_upgrade--SQUASHED' into Ghidra_9.2

This commit is contained in:
ghidra1 2020-09-29 10:23:16 -04:00
commit 39ef49d1d1
10 changed files with 390 additions and 120 deletions

View File

@ -59,10 +59,10 @@ int objdump_sprintf (SFILE *f, const char *format, ...)
void configureDisassembleInfo(bfd* abfd, void configureDisassembleInfo(bfd* abfd,
disassemble_info* info, disassemble_info* info,
enum bfd_architecture arch, enum bfd_architecture arch,
unsigned long mach, unsigned long mach,
enum bfd_endian end) enum bfd_endian end)
{ {
memset(sfile.buffer, 0x00, BUFF_SIZE); memset(sfile.buffer, 0x00, BUFF_SIZE);
@ -79,11 +79,11 @@ void configureDisassembleInfo(bfd* abfd,
} }
disassembler_ftype configureBfd(bfd* abfd, disassembler_ftype configureBfd(bfd* abfd,
enum bfd_architecture arch, enum bfd_architecture arch,
unsigned long mach, unsigned long mach,
enum bfd_endian endian, enum bfd_endian endian,
disassemble_info* DI, disassemble_info* DI,
disassembler_ftype* disassemble_fn) disassembler_ftype* disassemble_fn)
{ {
struct bfd_target *xvec; struct bfd_target *xvec;
@ -110,7 +110,7 @@ disassembler_ftype configureBfd(bfd* abfd,
/* /*
bfd_error_type err = bfd_get_error(); bfd_error_type err = bfd_get_error();
printf("bfd_error_msg: %s.\n", bfd_errmsg(err)); printf("bfd_error_msg: %s.\n", bfd_errmsg(err));
*/ */
/* Use libopcodes to locate a suitable disassembler. */ /* Use libopcodes to locate a suitable disassembler. */
*disassemble_fn = NULL; *disassemble_fn = NULL;
@ -118,17 +118,17 @@ disassembler_ftype configureBfd(bfd* abfd,
if (!*disassemble_fn){ if (!*disassemble_fn){
printf("can't disassemble for arch 0x%08X, mach 0x%08lX\n", arch, mach); printf("can't disassemble for arch 0x%08X, mach 0x%08lX\n", arch, mach);
exit(1); exit(1);
} }
return *disassemble_fn; return *disassemble_fn;
} }
int disassemble_buffer( disassembler_ftype disassemble_fn, int disassemble_buffer( disassembler_ftype disassemble_fn,
disassemble_info *info, disassemble_info *info,
int* offset, int* offset,
PDIS_INFO pDisInfo) PDIS_INFO pDisInfo)
{ {
int i, j, size = 0; int i, j, size = 0;
int len = 0; int len = 0;
@ -174,15 +174,15 @@ int disassemble_buffer( disassembler_ftype disassemble_fn,
} }
} }
END: END:
return size; return size;
} }
void processBuffer(unsigned char* buff, void processBuffer(unsigned char* buff,
int buff_len, int buff_len,
bfd_vma buff_vma, bfd_vma buff_vma,
disassembler_ftype disassemble_fn, disassembler_ftype disassemble_fn,
struct disassemble_info* DI) struct disassemble_info* DI)
{ {
int bytesConsumed = -1; int bytesConsumed = -1;
int offset = 0; int offset = 0;
@ -199,12 +199,12 @@ void processBuffer(unsigned char* buff,
bytesConsumed = disassemble_buffer( disassemble_fn, DI, &offset, &(disassemblyInfoBuffer[numDisassemblies++])); bytesConsumed = disassemble_buffer( disassemble_fn, DI, &offset, &(disassemblyInfoBuffer[numDisassemblies++]));
} }
for (i = 0; i < numDisassemblies; i++) { for (i = 0; i < numDisassemblies; i++) {
printf("%s\nInfo: %d,%d,%d,%d,%d\n", disassemblyInfoBuffer[i].disassemblyString, printf("%s\nInfo: %d,%d,%d,%d,%d\n", disassemblyInfoBuffer[i].disassemblyString,
disassemblyInfoBuffer[i].count, disassemblyInfoBuffer[i].count,
disassemblyInfoBuffer[i].insn_info_valid, disassemblyInfoBuffer[i].insn_info_valid,
disassemblyInfoBuffer[i].branch_delay_insns, disassemblyInfoBuffer[i].branch_delay_insns,
disassemblyInfoBuffer[i].data_size, disassemblyInfoBuffer[i].data_size,
disassemblyInfoBuffer[i].insn_type); disassemblyInfoBuffer[i].insn_type);
} }
} }
@ -256,7 +256,7 @@ int main(int argc, char* argv[]){
// if arch starts with 0x, then parse a number // if arch starts with 0x, then parse a number
// else lookup the string in the table to get the arch, ignore the mach // else lookup the string in the table to get the arch, ignore the mach
if (arch_str[0] == '0' && arch_str[1] == 'x') { if (arch_str[0] == '0' && arch_str[1] == 'x') {
sscanf(arch_str, "%10X", &arch); sscanf(arch_str, "%10X", &arch);
} else { } else {
const char** archList = bfd_arch_list(); const char** archList = bfd_arch_list();
const bfd_arch_info_type* ait; const bfd_arch_info_type* ait;
@ -271,8 +271,8 @@ int main(int argc, char* argv[]){
archList++; archList++;
} }
if (ait == NULL) { if (ait == NULL) {
printf("Couldn't find arch %s\n", arch_str); printf("Couldn't find arch %s\n", arch_str);
return(-1); return(-1);
} }
} }
@ -294,11 +294,6 @@ int main(int argc, char* argv[]){
stdin_mode = 1; // use STDIN stdin_mode = 1; // use STDIN
} }
unsigned char byteBuffer[BYTE_BUFFER_SIZE];
char byteStringBuffer[(BYTE_BUFFER_SIZE*2)];
char addressStringBuffer[128];
if (endian == BFD_ENDIAN_BIG){ if (endian == BFD_ENDIAN_BIG){
strcat(elf_file_location, BIG_ELF_FILE); strcat(elf_file_location, BIG_ELF_FILE);
} }
@ -306,47 +301,59 @@ int main(int argc, char* argv[]){
strcat(elf_file_location, LITTLE_ELF_FILE); strcat(elf_file_location, LITTLE_ELF_FILE);
} }
bfd_init();
while (stdin_mode) { while (stdin_mode) {
//bfd_init();
// convert user input AsciiHex to Binary data for processing // convert user input AsciiHex to Binary data for processing
char tmp[3]; char tmp[3];
unsigned int byteValue; unsigned int byteValue;
tmp[0] = tmp[1] = tmp[2] = 0x00; tmp[0] = tmp[1] = tmp[2] = 0x00;
char disassemblerOptions[128] = {0};
unsigned char byteBuffer[BYTE_BUFFER_SIZE] = {0};
char byteStringBuffer[(BYTE_BUFFER_SIZE*2)] = {0};
char addressStringBuffer[128] = {0};
char bytesAndOptionsBuffer[BYTE_BUFFER_SIZE*2 + sizeof(disassemblerOptions)] = {0};
if (stdin_mode == 1) { // use stdin if (stdin_mode == 1) { // use stdin
// read in the address // read in the address
if (fgets(addressStringBuffer, sizeof(addressStringBuffer), stdin)) { if (fgets(addressStringBuffer, sizeof(addressStringBuffer), stdin)) {
//fprintf(stderr, "read: %s\n", addressStringBuffer);
//char *p = strchr(addressStringBuffer, '\n');
//if (p) {
// *p = '\0';
//}
sscanf(addressStringBuffer, "%18lX", &offset); sscanf(addressStringBuffer, "%18lX", &offset);
} }
//getchar(); //Read in the rest of the input. There are two possible styles:
// read in the ASCII hex string from stdin //"old": input is just the bytes to disassemble
if (fgets(byteStringBuffer, sizeof(byteStringBuffer), stdin)) { //"new": input = bytes"*"<disassmbler_options>
//for compatibility reasons, handle both styles
//fprintf(stderr, "read: %s\n", byteStringBuffer); if (fgets(bytesAndOptionsBuffer, sizeof(bytesAndOptionsBuffer), stdin)) {
// remove trailing newline char *p = strchr(bytesAndOptionsBuffer, '*');
char *p = strchr(byteStringBuffer, '\n');
if (p) { if (p) {
*p = '\0'; strncpy(byteStringBuffer,bytesAndOptionsBuffer,(int) (p - bytesAndOptionsBuffer));
strncpy(disassemblerOptions,p+1,sizeof(disassemblerOptions));
p = strchr(disassemblerOptions,'\n');
if (p){
*p = '\0';
}
}
else {
//no "*" in the string, so no disassembly options
//replace newline with null terminator
strncpy(byteStringBuffer, bytesAndOptionsBuffer, sizeof(byteStringBuffer));
p = strchr(byteStringBuffer,'\n');
if (p){
*p = '\0';
}
} }
//if (strcmp(byteStringBuffer, "EOF") == 0) {
//return 0; // terminate on EOF string
//}
} else {
fprintf(stderr, "exiting, no ASCII hex found\n");
return 0; // finished! #TODO
} }
else {
} else { fprintf(stderr, "exiting, no ASCII hex found\n");
return 0; // finished! #TODO
}
}
else {
if(strlen(byteString) > BYTE_BUFFER_SIZE*2) { if(strlen(byteString) > BYTE_BUFFER_SIZE*2) {
fprintf(stderr, "Max ascii string size is %d you provided: %lu chars. Exiting.\n", BYTE_BUFFER_SIZE*2, fprintf(stderr, "Max ascii string size is %d you provided: %lu chars. Exiting.\n", BYTE_BUFFER_SIZE*2,
strlen(byteString)); strlen(byteString));
exit(-1); exit(-1);
} }
strncpy(byteStringBuffer, byteString, BYTE_BUFFER_SIZE*2); strncpy(byteStringBuffer, byteString, BYTE_BUFFER_SIZE*2);
@ -378,9 +385,9 @@ int main(int argc, char* argv[]){
for(j=0; j < BYTE_BUFFER_SIZE; j++){ for(j=0; j < BYTE_BUFFER_SIZE; j++){
printf("0x%02X ", byteBuffer[j]); printf("0x%02X ", byteBuffer[j]);
} }
*/ */
bfd_init( ); //bfd_init( );
target = argv[1]; target = argv[1];
bfd_set_default_target(target); bfd_set_default_target(target);
@ -420,14 +427,17 @@ int main(int argc, char* argv[]){
/* /*
bfd_error_type err = bfd_get_error(); bfd_error_type err = bfd_get_error();
printf("bfd_error_msg: %s.\n", bfd_errmsg(err)); printf("bfd_error_msg: %s.\n", bfd_errmsg(err));
*/ */
/*if (disassemblerOptions[0] != '\0'){
DI.disassembler_options = disassemblerOptions;
}*/
configureBfd(bfdfile, arch, mach, endian, &DI, &disassemble_fn); configureBfd(bfdfile, arch, mach, endian, &DI, &disassemble_fn);
/* /*
err = bfd_get_error(); err = bfd_get_error();
printf("bfd_error_msg: %s.\n", bfd_errmsg(err)); printf("bfd_error_msg: %s.\n", bfd_errmsg(err));
*/ */
if (disassemble_fn == NULL){ if (disassemble_fn == NULL){
fprintf(stderr, "Error: disassemble_fn is NULL. Nothing I can do.\n"); fprintf(stderr, "Error: disassemble_fn is NULL. Nothing I can do.\n");
@ -437,8 +447,12 @@ int main(int argc, char* argv[]){
/* /*
printf("the disassemble_fn func pointer is: 0x%08X.\n", disassemble_fn); printf("the disassemble_fn func pointer is: 0x%08X.\n", disassemble_fn);
printf("We can try to disassemble for this arch/mach. calling disassemble_init_for_target().\n"); printf("We can try to disassemble for this arch/mach. calling disassemble_init_for_target().\n");
*/ */
disassemble_init_for_target(&DI); disassemble_init_for_target(&DI);
if (disassemblerOptions[0] != '\0'){
DI.disassembler_options = disassemblerOptions;
}
// go diassemble the buffer and build up the result in a accumulator string buffer. // go diassemble the buffer and build up the result in a accumulator string buffer.
processBuffer(byteBuffer, size >> 1, offset, disassemble_fn, &DI); // processBuffer(byteBuffer, size >> 1, offset, disassemble_fn, &DI); //

View File

@ -23,6 +23,8 @@ public interface ExternalDisassembler extends ExtensionPoint {
public String getDisassembly(CodeUnit cu) throws Exception; public String getDisassembly(CodeUnit cu) throws Exception;
public String getDisassemblyDisplayPrefix(CodeUnit cu) throws Exception;
public String getDisassemblyOfBytes(Language language, boolean isBigEndian, long address, public String getDisassemblyOfBytes(Language language, boolean isBigEndian, long address,
byte[] byteString) throws Exception; byte[] byteString) throws Exception;

View File

@ -150,7 +150,10 @@ public class ExternalDisassemblyFieldFactory extends FieldFactory {
if (disassembly == null) { if (disassembly == null) {
return null; return null;
} }
String prefix = disassembler.getDisassemblyDisplayPrefix(cu);
if (prefix != null) {
disassembly = prefix + " " + disassembly;
}
return disassembly; return disassembly;
} }

View File

@ -18,19 +18,23 @@ package ghidra.app.util.disassemble;
import java.io.*; import java.io.*;
import java.util.*; import java.util.*;
import org.apache.commons.lang3.StringUtils;
import org.jdom.*;
import org.jdom.input.SAXBuilder;
import generic.jar.ResourceFile; import generic.jar.ResourceFile;
import ghidra.app.util.bin.ByteProvider; import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.MemoryByteProvider; import ghidra.app.util.bin.MemoryByteProvider;
import ghidra.framework.*; import ghidra.framework.*;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressOutOfBoundsException; import ghidra.program.model.address.AddressOutOfBoundsException;
import ghidra.program.model.lang.Language; import ghidra.program.model.lang.*;
import ghidra.program.model.lang.LanguageID; import ghidra.program.model.listing.*;
import ghidra.program.model.listing.CodeUnit;
import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.MemBuffer; import ghidra.program.model.mem.MemBuffer;
import ghidra.program.model.mem.MemoryAccessException; import ghidra.program.model.mem.MemoryAccessException;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.xml.XmlUtilities;
import util.CollectionUtils;
public class GNUExternalDisassembler implements ExternalDisassembler { public class GNUExternalDisassembler implements ExternalDisassembler {
@ -39,6 +43,7 @@ public class GNUExternalDisassembler implements ExternalDisassembler {
// magic values for gdis that direct it to read bytes from stdin // magic values for gdis that direct it to read bytes from stdin
private static final String READ_FROM_STDIN_PARAMETER = "stdin"; private static final String READ_FROM_STDIN_PARAMETER = "stdin";
private static final String SEPARATOR_CHARACTER = "\n"; private static final String SEPARATOR_CHARACTER = "\n";
private static final String OPTIONS_SEPARATOR = "*";
private static final String ADDRESS_OUT_OF_BOUNDS = "is out of bounds."; private static final String ADDRESS_OUT_OF_BOUNDS = "is out of bounds.";
private static final String ENDING_STRING = "EOF"; private static final String ENDING_STRING = "EOF";
private static final int NUM_BYTES = 32; private static final int NUM_BYTES = 32;
@ -48,6 +53,8 @@ public class GNUExternalDisassembler implements ExternalDisassembler {
private static final String GDIS_EXE = private static final String GDIS_EXE =
Platform.CURRENT_PLATFORM.getOperatingSystem() == OperatingSystem.WINDOWS ? "gdis.exe" Platform.CURRENT_PLATFORM.getOperatingSystem() == OperatingSystem.WINDOWS ? "gdis.exe"
: "gdis"; : "gdis";
private static final String EMPTY_DISASSEMBLER_OPTIONS = "";
private static final String GDIS_OPTIONS_FILENAME_PROPERTY = "gdis.disassembler.options.file";
private static HashMap<String, File> languageGdisMap; private static HashMap<String, File> languageGdisMap;
private static File defaultGdisExecFile; private static File defaultGdisExecFile;
@ -82,6 +89,21 @@ public class GNUExternalDisassembler implements ExternalDisassembler {
return gdisConfig != null && gdisConfig.architecture != UNSUPPORTED; return gdisConfig != null && gdisConfig.architecture != UNSUPPORTED;
} }
@Override
public String getDisassemblyDisplayPrefix(CodeUnit cu) throws Exception {
GdisConfig gdisConfig = checkLanguage(cu.getProgram().getLanguage());
if (gdisConfig == null || gdisConfig.architecture == UNSUPPORTED) {
return null;
}
Register contextRegister = gdisConfig.getContextRegister();
if (contextRegister == null) {
return null;
}
long value = getContextRegisterValue(cu, contextRegister);
String option = gdisConfig.getDisplayPrefixMap().get(value);
return option;
}
private static void reportMultipleMappings(Language language) { private static void reportMultipleMappings(Language language) {
List<String> externalNames = language.getLanguageDescription().getExternalNames("gnu"); List<String> externalNames = language.getLanguageDescription().getExternalNames("gnu");
if (externalNames != null && externalNames.size() > 1) { if (externalNames != null && externalNames.size() > 1) {
@ -89,8 +111,9 @@ public class GNUExternalDisassembler implements ExternalDisassembler {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
boolean prependSeparator = false; boolean prependSeparator = false;
for (String name : externalNames) { for (String name : externalNames) {
if (prependSeparator) if (prependSeparator) {
sb.append(", "); sb.append(", ");
}
sb.append(name); sb.append(name);
prependSeparator = true; prependSeparator = true;
} }
@ -110,11 +133,17 @@ public class GNUExternalDisassembler implements ExternalDisassembler {
String machineId; String machineId;
File gdisExecFile; File gdisExecFile;
boolean usingDefault; boolean usingDefault;
Register contextRegister;
Map<Long, String> valueToOptionString;
Map<Long, String> valueToDisplayPrefix;
Language lang;
String globalDisassemblerOptions;
GdisConfig(Language language, boolean isBigEndian) { GdisConfig(Language language, boolean isBigEndian) {
this.languageId = language.getLanguageID().toString(); this.languageId = language.getLanguageID().toString();
this.isBigEndian = isBigEndian; this.isBigEndian = isBigEndian;
this.lang = language;
List<String> architectures = language.getLanguageDescription().getExternalNames("gnu"); List<String> architectures = language.getLanguageDescription().getExternalNames("gnu");
//get first non-null //get first non-null
@ -143,12 +172,123 @@ public class GNUExternalDisassembler implements ExternalDisassembler {
gdisExecFile = defaultGdisExecFile; gdisExecFile = defaultGdisExecFile;
usingDefault = true; usingDefault = true;
} }
List<String> gDisOptionsFile =
language.getLanguageDescription().getExternalNames(GDIS_OPTIONS_FILENAME_PROPERTY);
if (!CollectionUtils.isBlank(gDisOptionsFile)) {
try {
parseGdisOptionsFile(gDisOptionsFile.get(0));
}
catch (IOException e) {
Msg.error(this, "Error reading gdis options file " + e.getMessage());
contextRegister = null;
valueToOptionString = null;
valueToDisplayPrefix = null;
}
}
} }
GdisConfig(Language lang) { GdisConfig(Language lang) {
this(lang, lang.isBigEndian()); this(lang, lang.isBigEndian());
} }
private void parseGdisOptionsFile(String fileName) throws IOException {
LanguageDescription desc = lang.getLanguageDescription();
if (!(desc instanceof SleighLanguageDescription)) {
throw new IOException("Not a Sleigh Language: " + lang.getLanguageID());
}
SleighLanguageDescription sld = (SleighLanguageDescription) desc;
ResourceFile defsFile = sld.getDefsFile();
ResourceFile parentFile = defsFile.getParentFile();
ResourceFile gdisOpts = new ResourceFile(parentFile, fileName);
SAXBuilder sax = XmlUtilities.createSecureSAXBuilder(false, false);
try (InputStream fis = gdisOpts.getInputStream()) {
Document doc = sax.build(fis);
Element rootElem = doc.getRootElement();
Element globalElement = rootElem.getChild("global");
if (globalElement != null) {
globalDisassemblerOptions = globalElement.getAttributeValue("optstring");
}
Element contextRegisterElement = rootElem.getChild("context_register");
if (contextRegisterElement == null) {
//no context_register element found in the xml file
//this is not necessarily an error - might only be a global optstring
//global optstring has already been parsed, so we're done
if (globalElement != null) {
Msg.info(this,
"no context register element in " + gdisOpts.getAbsolutePath());
return;
}
//no context register element or global element, error
throw new JDOMException(
"No context_register element or global element in gdis options file");
}
if (contextRegisterElement.getContentSize() == 0) {
throw new JDOMException("No context register name provided.");
}
String contextRegisterName = contextRegisterElement.getContent(0).getValue();
contextRegister = lang.getRegister(contextRegisterName);
if (contextRegister == null) {
//the context register named in the xml file does not exist in the sleigh language
//this is an error
throw new JDOMException("Unknown context register " + contextRegisterName +
" for language " + lang.getLanguageID().getIdAsString());
}
valueToOptionString = new HashMap<>();
valueToDisplayPrefix = new HashMap<>();
Element options = rootElem.getChild("options");
List<Element> optList = options.getChildren("option");
for (Element opt : optList) {
Long value = Long.decode(opt.getAttributeValue("value"));
String optString = opt.getAttributeValue("optstring");
valueToOptionString.put(value, optString);
String displayPrefix = opt.getAttributeValue("display_prefix");
valueToDisplayPrefix.put(value, displayPrefix);
}
}
catch (JDOMException e) {
Msg.error(this, "Error reading " + fileName + ": " + e.getMessage());
contextRegister = null;
valueToOptionString = null;
valueToDisplayPrefix = null;
}
}
/**
* Returns the global disassembler options
* @return global option string, or {@code null} if the
* global is unspecified.
*/
public String getGlobalDisassemblerOptions() {
return globalDisassemblerOptions;
}
/**
* Return the context register determine by the gdis options file
* @return the context register
*/
public Register getContextRegister() {
return contextRegister;
}
/**
* Returns the map from context register values to gdis disassembler options
* @return map values->options
*/
public Map<Long, String> getOptionsMap() {
return valueToOptionString;
}
/**
* Returns the map from context register values to disassembly display prefixes
* @return map values->prefixes
*/
public Map<Long, String> getDisplayPrefixMap() {
return valueToDisplayPrefix;
}
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (!(obj instanceof GdisConfig)) { if (!(obj instanceof GdisConfig)) {
@ -260,7 +400,7 @@ public class GNUExternalDisassembler implements ExternalDisassembler {
String bytes = getBytes(byteProvider, blockSize); String bytes = getBytes(byteProvider, blockSize);
return runDisassembler(gdisConfig, address, bytes); return runDisassembler(gdisConfig, address, bytes, EMPTY_DISASSEMBLER_OPTIONS);
} }
public List<GnuDisassembledInstruction> getBlockDisassembly(Program program, Address addr, public List<GnuDisassembledInstruction> getBlockDisassembly(Program program, Address addr,
@ -272,8 +412,8 @@ public class GNUExternalDisassembler implements ExternalDisassembler {
int blockSize = pow2(blockSizeFactor); int blockSize = pow2(blockSizeFactor);
Address blockAddr = addr.getNewAddress(addr.getOffset() & -blockSize); // block Address blockAddr = addr.getNewAddress(addr.getOffset() & -blockSize); // block
// aligned // aligned
// address // address
return getBlockDisassembly(program.getLanguage(), blockAddr, blockSizeFactor, return getBlockDisassembly(program.getLanguage(), blockAddr, blockSizeFactor,
new MemoryByteProvider(program.getMemory(), blockAddr)); new MemoryByteProvider(program.getMemory(), blockAddr));
@ -301,7 +441,37 @@ public class GNUExternalDisassembler implements ExternalDisassembler {
return ""; return "";
} }
List<GnuDisassembledInstruction> disassembly = runDisassembler(gdisConfig, address, bytes); String disOptions = EMPTY_DISASSEMBLER_OPTIONS;
String globalOptions = gdisConfig.getGlobalDisassemblerOptions();
boolean hasGlobal = false;
if (globalOptions != null) {
hasGlobal = true;
//set the disOptions to the global options here in case there are global
//options but no options for context register values
disOptions = globalOptions;
}
Register contextRegister = gdisConfig.getContextRegister();
if (contextRegister != null) {
long value = getContextRegisterValue(cu, contextRegister);
String contextRegisterValueOption = gdisConfig.getOptionsMap().get(value);
if (contextRegisterValueOption == null) {
Msg.warn(this, "No option for value " + value + " of context register " +
contextRegister.getName());
}
else {
//need to put a comma between the global options and the options
//for this context register value
if (hasGlobal) {
disOptions = globalOptions + "," + contextRegisterValueOption;
}
//no global options, just send the options for this context register
else {
disOptions = contextRegisterValueOption;
}
}
}
List<GnuDisassembledInstruction> disassembly =
runDisassembler(gdisConfig, address, bytes, disOptions);
if (disassembly == null || disassembly.size() == 0 || disassembly.get(0) == null) { if (disassembly == null || disassembly.size() == 0 || disassembly.get(0) == null) {
return "(bad)"; return "(bad)";
@ -324,7 +494,7 @@ public class GNUExternalDisassembler implements ExternalDisassembler {
String address = "0x" + Long.toHexString(addressOffset); String address = "0x" + Long.toHexString(addressOffset);
List<GnuDisassembledInstruction> disassembly = List<GnuDisassembledInstruction> disassembly =
runDisassembler(gdisConfig, address, bytesString); runDisassembler(gdisConfig, address, bytesString, EMPTY_DISASSEMBLER_OPTIONS);
if (disassembly == null || disassembly.isEmpty() || disassembly.get(0) == null) { if (disassembly == null || disassembly.isEmpty() || disassembly.get(0) == null) {
return "(bad)"; return "(bad)";
@ -332,14 +502,26 @@ public class GNUExternalDisassembler implements ExternalDisassembler {
return disassembly.get(0).toString(); return disassembly.get(0).toString();
} }
private long getContextRegisterValue(CodeUnit cu, Register contextRegister) {
ProgramContext context = cu.getProgram().getProgramContext();
RegisterValue value = context.getRegisterValue(contextRegister, cu.getAddress());
if (value != null) {
return value.getUnsignedValue().longValue();
}
//we tried, return 0 to match SLEIGH default
return 0;
}
private String converBytesToString(byte[] bytes) { private String converBytesToString(byte[] bytes) {
String byteString = null; String byteString = null;
for (byte thisByte : bytes) { for (byte thisByte : bytes) {
String thisByteString = Integer.toHexString(thisByte); String thisByteString = Integer.toHexString(thisByte);
if (thisByteString.length() == 1) if (thisByteString.length() == 1) {
thisByteString = "0" + thisByteString; // pad single digits thisByteString = "0" + thisByteString; // pad single digits
if (thisByteString.length() > 2) }
if (thisByteString.length() > 2) {
thisByteString = thisByteString.substring(thisByteString.length() - 2); thisByteString = thisByteString.substring(thisByteString.length() - 2);
}
// append this byte's hex string to the larger word length string // append this byte's hex string to the larger word length string
byteString = byteString + thisByteString; byteString = byteString + thisByteString;
} }
@ -402,7 +584,7 @@ public class GNUExternalDisassembler implements ExternalDisassembler {
} }
private List<GnuDisassembledInstruction> runDisassembler(GdisConfig gdisConfig, private List<GnuDisassembledInstruction> runDisassembler(GdisConfig gdisConfig,
String addrString, String bytes) throws IOException { String addrString, String bytes, String disassemblerOptions) throws IOException {
// if this is the first time running the disassembler process, or a // if this is the first time running the disassembler process, or a
// parameter has changed (notably, not the address--we pass that in // parameter has changed (notably, not the address--we pass that in
@ -414,8 +596,9 @@ public class GNUExternalDisassembler implements ExternalDisassembler {
if (disassemblerProcess == null || !sameConfig) { if (disassemblerProcess == null || !sameConfig) {
if (!setupDisassembler(gdisConfig)) if (!setupDisassembler(gdisConfig)) {
return null; return null;
}
outputWriter = new OutputStreamWriter(disassemblerProcess.getOutputStream()); outputWriter = new OutputStreamWriter(disassemblerProcess.getOutputStream());
@ -432,7 +615,14 @@ public class GNUExternalDisassembler implements ExternalDisassembler {
return null; // if process previously died return nothing - quickly return null; // if process previously died return nothing - quickly
} }
String disassemblyRequest = addrString + SEPARATOR_CHARACTER + bytes + SEPARATOR_CHARACTER; String disassemblyRequest = addrString + SEPARATOR_CHARACTER + bytes;
if (StringUtils.isEmpty(disassemblerOptions)) {
disassemblyRequest += '\n';
}
else {
disassemblyRequest += OPTIONS_SEPARATOR + disassemblerOptions + SEPARATOR_CHARACTER;
}
try { try {
outputWriter.write(disassemblyRequest); outputWriter.write(disassemblyRequest);
outputWriter.flush(); outputWriter.flush();

View File

@ -3,6 +3,7 @@ Module.manifest||GHIDRA||||END|
build.gradle||GHIDRA||||END| build.gradle||GHIDRA||||END|
data/languages/ARM.cspec||GHIDRA||||END| data/languages/ARM.cspec||GHIDRA||||END|
data/languages/ARM.dwarf||GHIDRA||||END| data/languages/ARM.dwarf||GHIDRA||||END|
data/languages/ARM.gdis||GHIDRA||||END|
data/languages/ARM.ldefs||GHIDRA||||END| data/languages/ARM.ldefs||GHIDRA||||END|
data/languages/ARM.opinion||GHIDRA||||END| data/languages/ARM.opinion||GHIDRA||||END|
data/languages/ARM.sinc||GHIDRA||||END| data/languages/ARM.sinc||GHIDRA||||END|

View File

@ -0,0 +1,41 @@
<!--
This file determines the disassembler options sent to the GNU external disassembler.
You can see which options are available for all architectures in the objdump man page.
Given a version of objdump compiled for a specific architecture, you can see what options
are available with "objdump -i -m"
The options for ARM are:
"reg-names-std" (the default)
"reg-names-apcs"
"reg-names-raw"
"reg-names-apcs"
"reg-names-special-apcs"
"force-thumb" (force thumb disassembly)
"no-force-thumb" (force arm disassembly)
(see the objdump manpage for the precise details about the different register
naming options)
"optstring" is the string of options, and "display_prefix" is an optional prefix prepended to the
external disassembly field. In this file, "A: " is prepended to ARM disassembly, and
"T: " is prepended to Thumb disassembly.
To send multiple options, concatenate them into a CSV list. For example, "no-force-thumb,reg-names-raw"
is a valid optstring. You can also have a "global" element whose "optstring" attribute is
always sent to the GNU disassembler.
If there is not a context register defined, the global optstring is sent by itself (see x86-16.gdis for
an example). If there is a context register defined, the global optstring is prepended to the
optstring determined by a context register value.
This file must be listed in the .ldefs file for the processor, e.g.
<external_name tool="gdis.disassembler.options.file" name="ARM.gdis"/>
-->
<gdis>
<context_register>TMode</context_register>
<options>
<option value="0x0" optstring="no-force-thumb" display_prefix = "A: "/>
<option value="0x1" optstring="force-thumb" display_prefix = "T: "/>
</options>
</gdis>

View File

@ -14,6 +14,7 @@
<compiler name="default" spec="ARM.cspec" id="default"/> <compiler name="default" spec="ARM.cspec" id="default"/>
<compiler name="Visual Studio" spec="ARM_win.cspec" id="windows"/> <compiler name="Visual Studio" spec="ARM_win.cspec" id="windows"/>
<external_name tool="gnu" name="iwmmxt"/> <external_name tool="gnu" name="iwmmxt"/>
<external_name tool="gdis.disassembler.options.file" name="ARM.gdis"/>
<external_name tool="IDA-PRO" name="arm"/> <external_name tool="IDA-PRO" name="arm"/>
<external_name tool="DWARF.register.mapping.file" name="ARMneon.dwarf"/> <external_name tool="DWARF.register.mapping.file" name="ARMneon.dwarf"/>
</language> </language>
@ -31,6 +32,7 @@
<compiler name="default" spec="ARM.cspec" id="default"/> <compiler name="default" spec="ARM.cspec" id="default"/>
<compiler name="Visual Studio" spec="ARM_win.cspec" id="windows"/> <compiler name="Visual Studio" spec="ARM_win.cspec" id="windows"/>
<external_name tool="gnu" name="iwmmxt"/> <external_name tool="gnu" name="iwmmxt"/>
<external_name tool="gdis.disassembler.options.file" name="ARM.gdis"/>
<external_name tool="IDA-PRO" name="arm"/> <external_name tool="IDA-PRO" name="arm"/>
<external_name tool="DWARF.register.mapping.file" name="ARMneon.dwarf"/> <external_name tool="DWARF.register.mapping.file" name="ARMneon.dwarf"/>
</language> </language>
@ -63,6 +65,7 @@
<description>Generic ARM/Thumb v8 big endian</description> <description>Generic ARM/Thumb v8 big endian</description>
<compiler name="default" spec="ARM.cspec" id="default"/> <compiler name="default" spec="ARM.cspec" id="default"/>
<external_name tool="gnu" name="iwmmxt"/> <external_name tool="gnu" name="iwmmxt"/>
<external_name tool="gdis.disassembler.options.file" name="ARM.gdis"/>
<external_name tool="IDA-PRO" name="armb"/> <external_name tool="IDA-PRO" name="armb"/>
<external_name tool="DWARF.register.mapping.file" name="ARMneon.dwarf"/> <external_name tool="DWARF.register.mapping.file" name="ARMneon.dwarf"/>
</language> </language>
@ -96,6 +99,7 @@
<compiler name="default" spec="ARM.cspec" id="default"/> <compiler name="default" spec="ARM.cspec" id="default"/>
<compiler name="Visual Studio" spec="ARM_win.cspec" id="windows"/> <compiler name="Visual Studio" spec="ARM_win.cspec" id="windows"/>
<external_name tool="gnu" name="iwmmxt"/> <external_name tool="gnu" name="iwmmxt"/>
<external_name tool="gdis.disassembler.options.file" name="ARM.gdis"/>
<external_name tool="IDA-PRO" name="arm"/> <external_name tool="IDA-PRO" name="arm"/>
<external_name tool="DWARF.register.mapping.file" name="ARMneon.dwarf"/> <external_name tool="DWARF.register.mapping.file" name="ARMneon.dwarf"/>
</language> </language>
@ -128,6 +132,7 @@
<description>Generic ARM/Thumb v7 big endian</description> <description>Generic ARM/Thumb v7 big endian</description>
<compiler name="default" spec="ARM.cspec" id="default"/> <compiler name="default" spec="ARM.cspec" id="default"/>
<external_name tool="gnu" name="iwmmxt"/> <external_name tool="gnu" name="iwmmxt"/>
<external_name tool="gdis.disassembler.options.file" name="ARM.gdis"/>
<external_name tool="IDA-PRO" name="armb"/> <external_name tool="IDA-PRO" name="armb"/>
<external_name tool="DWARF.register.mapping.file" name="ARMneon.dwarf"/> <external_name tool="DWARF.register.mapping.file" name="ARMneon.dwarf"/>
</language> </language>
@ -174,6 +179,7 @@
<description>Generic ARM/Thumb v6 little endian</description> <description>Generic ARM/Thumb v6 little endian</description>
<compiler name="default" spec="ARM_v45.cspec" id="default"/> <compiler name="default" spec="ARM_v45.cspec" id="default"/>
<external_name tool="gnu" name="xscale"/> <external_name tool="gnu" name="xscale"/>
<external_name tool="gdis.disassembler.options.file" name="ARM.gdis"/>
<external_name tool="IDA-PRO" name="arm"/> <external_name tool="IDA-PRO" name="arm"/>
<external_name tool="DWARF.register.mapping.file" name="ARM.dwarf"/> <external_name tool="DWARF.register.mapping.file" name="ARM.dwarf"/>
<!-- change DWARF register mapping to ARMneon.dwarf if VFPv2 is enabled --> <!-- change DWARF register mapping to ARMneon.dwarf if VFPv2 is enabled -->
@ -192,6 +198,7 @@
<description>Generic ARM/Thumb v6 big endian</description> <description>Generic ARM/Thumb v6 big endian</description>
<compiler name="default" spec="ARM_v45.cspec" id="default"/> <compiler name="default" spec="ARM_v45.cspec" id="default"/>
<external_name tool="gnu" name="xscale"/> <external_name tool="gnu" name="xscale"/>
<external_name tool="gdis.disassembler.options.file" name="ARM.gdis"/>
<external_name tool="IDA-PRO" name="armb"/> <external_name tool="IDA-PRO" name="armb"/>
<external_name tool="DWARF.register.mapping.file" name="ARM.dwarf"/> <external_name tool="DWARF.register.mapping.file" name="ARM.dwarf"/>
<!-- change DWARF register mapping to ARMneon.dwarf if VFPv2 is enabled --> <!-- change DWARF register mapping to ARMneon.dwarf if VFPv2 is enabled -->
@ -210,6 +217,7 @@
<description>Generic ARM/Thumb v5 little endian (T-variant)</description> <description>Generic ARM/Thumb v5 little endian (T-variant)</description>
<compiler name="default" spec="ARM_v45.cspec" id="default"/> <compiler name="default" spec="ARM_v45.cspec" id="default"/>
<external_name tool="gnu" name="armv5t"/> <external_name tool="gnu" name="armv5t"/>
<external_name tool="gdis.disassembler.options.file" name="ARM.gdis"/>
<external_name tool="IDA-PRO" name="arm"/> <external_name tool="IDA-PRO" name="arm"/>
<external_name tool="DWARF.register.mapping.file" name="ARM.dwarf"/> <external_name tool="DWARF.register.mapping.file" name="ARM.dwarf"/>
</language> </language>
@ -226,6 +234,7 @@
<description>Generic ARM/Thumb v5 big endian (T-variant)</description> <description>Generic ARM/Thumb v5 big endian (T-variant)</description>
<compiler name="default" spec="ARM_v45.cspec" id="default"/> <compiler name="default" spec="ARM_v45.cspec" id="default"/>
<external_name tool="gnu" name="armv5t"/> <external_name tool="gnu" name="armv5t"/>
<external_name tool="gdis.disassembler.options.file" name="ARM.gdis"/>
<external_name tool="IDA-PRO" name="armb"/> <external_name tool="IDA-PRO" name="armb"/>
<external_name tool="DWARF.register.mapping.file" name="ARM.dwarf"/> <external_name tool="DWARF.register.mapping.file" name="ARM.dwarf"/>
</language> </language>
@ -274,6 +283,7 @@
<description>Generic ARM/Thumb v4 little endian (T-variant)</description> <description>Generic ARM/Thumb v4 little endian (T-variant)</description>
<compiler name="default" spec="ARM_v45.cspec" id="default"/> <compiler name="default" spec="ARM_v45.cspec" id="default"/>
<external_name tool="gnu" name="armv4t"/> <external_name tool="gnu" name="armv4t"/>
<external_name tool="gdis.disassembler.options.file" name="ARM.gdis"/>
<external_name tool="IDA-PRO" name="arm"/> <external_name tool="IDA-PRO" name="arm"/>
<external_name tool="DWARF.register.mapping.file" name="ARM.dwarf"/> <external_name tool="DWARF.register.mapping.file" name="ARM.dwarf"/>
</language> </language>
@ -290,6 +300,7 @@
<description>Generic ARM/Thumb v4 big endian (T-variant)</description> <description>Generic ARM/Thumb v4 big endian (T-variant)</description>
<compiler name="default" spec="ARM_v45.cspec" id="default"/> <compiler name="default" spec="ARM_v45.cspec" id="default"/>
<external_name tool="gnu" name="armv4t"/> <external_name tool="gnu" name="armv4t"/>
<external_name tool="gdis.disassembler.options.file" name="ARM.gdis"/>
<external_name tool="IDA-PRO" name="armb"/> <external_name tool="IDA-PRO" name="armb"/>
<external_name tool="DWARF.register.mapping.file" name="ARM.dwarf"/> <external_name tool="DWARF.register.mapping.file" name="ARM.dwarf"/>
</language> </language>

View File

@ -30,6 +30,7 @@ data/languages/sha.sinc||GHIDRA||||END|
data/languages/smx.sinc||GHIDRA||||END| data/languages/smx.sinc||GHIDRA||||END|
data/languages/x86-16-real.pspec||GHIDRA||||END| data/languages/x86-16-real.pspec||GHIDRA||||END|
data/languages/x86-16.cspec||GHIDRA||||END| data/languages/x86-16.cspec||GHIDRA||||END|
data/languages/x86-16.gdis||GHIDRA||||END|
data/languages/x86-16.pspec||GHIDRA||||END| data/languages/x86-16.pspec||GHIDRA||||END|
data/languages/x86-64-gcc.cspec||GHIDRA||||END| data/languages/x86-64-gcc.cspec||GHIDRA||||END|
data/languages/x86-64-win.cspec||GHIDRA||||END| data/languages/x86-64-win.cspec||GHIDRA||||END|

View File

@ -0,0 +1,3 @@
<gdis>
<global optstring="intel"/>
</gdis>

View File

@ -59,6 +59,8 @@
<external_name tool="IDA-PRO" name="80486r"/> <external_name tool="IDA-PRO" name="80486r"/>
<external_name tool="IDA-PRO" name="80586r"/> <external_name tool="IDA-PRO" name="80586r"/>
<external_name tool="IDA-PRO" name="metapc"/> <external_name tool="IDA-PRO" name="metapc"/>
<external_name tool="gnu" name="i8086"/>
<external_name tool="gdis.disassembler.options.file" name="x86-16.gdis"/>
</language> </language>
<language processor="x86" <language processor="x86"
endian="little" endian="little"
@ -72,6 +74,8 @@
<description>Intel/AMD 16-bit x86 Protected Mode</description> <description>Intel/AMD 16-bit x86 Protected Mode</description>
<compiler name="default" spec="x86-16.cspec" id="default"/> <compiler name="default" spec="x86-16.cspec" id="default"/>
<external_name tool="IDA-PRO" name="8086p"/> <external_name tool="IDA-PRO" name="8086p"/>
<external_name tool="gnu" name="i8086"/>
<external_name tool="gdis.disassembler.options.file" name="x86-16.gdis"/>
</language> </language>
<language processor="x86" <language processor="x86"
endian="little" endian="little"