GP-49 external disassembly field can now switch based upon context (implemented for ARM/Thumb)

This commit is contained in:
ghidra1 2020-09-29 10:22:46 -04:00
parent 6677daca41
commit 356ea446c7
10 changed files with 390 additions and 120 deletions

View File

@ -21,7 +21,7 @@ void listSupportedArchMachTargets(void)
const char** targetList;
const char** archList;
int i, j;
targetList = bfd_target_list();
if(targetList != NULL){
for(i=0, j=0; targetList[i] !=0; i++){
@ -29,7 +29,7 @@ void listSupportedArchMachTargets(void)
}
}
printf("\ndone with targetList.\n");
archList = bfd_arch_list();
if(archList != NULL){
for(i=0, j=0; archList[i] !=0; i++){
@ -44,29 +44,29 @@ void listSupportedArchMachTargets(void)
/* sprintf to a "stream". */
int objdump_sprintf (SFILE *f, const char *format, ...)
{
int i;
size_t n;
va_list args;
va_start (args, format);
n = vsnprintf (f->buffer + f->pos, BUFF_SIZE, format, args);
strncat(disassembled_buffer, f->buffer, n);
va_end (args);
return n;
}
void configureDisassembleInfo(bfd* abfd,
disassemble_info* info,
enum bfd_architecture arch,
unsigned long mach,
enum bfd_endian end)
disassemble_info* info,
enum bfd_architecture arch,
unsigned long mach,
enum bfd_endian end)
{
memset(sfile.buffer, 0x00, BUFF_SIZE);
INIT_DISASSEMBLE_INFO(*info, stdout, objdump_sprintf);
info->arch = (enum bfd_architecture) arch;
info->mach = mach;
@ -79,24 +79,24 @@ void configureDisassembleInfo(bfd* abfd,
}
disassembler_ftype configureBfd(bfd* abfd,
enum bfd_architecture arch,
unsigned long mach,
enum bfd_endian endian,
disassemble_info* DI,
disassembler_ftype* disassemble_fn)
enum bfd_architecture arch,
unsigned long mach,
enum bfd_endian endian,
disassemble_info* DI,
disassembler_ftype* disassemble_fn)
{
struct bfd_target *xvec;
abfd->flags |= EXEC_P;
// set up xvec byteorder.
xvec = (struct bfd_target *) malloc (sizeof (struct bfd_target));
memset(xvec, 0x00, sizeof (struct bfd_target));
memcpy (xvec, abfd->xvec, sizeof (struct bfd_target));
xvec->byteorder = endian;
abfd->xvec = xvec;
configureDisassembleInfo(abfd, DI, arch, mach, endian);
if(endian == BFD_ENDIAN_BIG){
bfd_big_endian(abfd);
@ -106,29 +106,29 @@ disassembler_ftype configureBfd(bfd* abfd,
bfd_little_endian(abfd);
DI->display_endian = DI->endian = BFD_ENDIAN_LITTLE;
}
/*
bfd_error_type err = bfd_get_error();
printf("bfd_error_msg: %s.\n", bfd_errmsg(err));
*/
*/
/* Use libopcodes to locate a suitable disassembler. */
*disassemble_fn = NULL;
*disassemble_fn = disassembler (arch, endian == BFD_ENDIAN_BIG, mach, abfd);
if (!*disassemble_fn){
printf("can't disassemble for arch 0x%08X, mach 0x%08lX\n", arch, mach);
exit(1);
}
return *disassemble_fn;
}
return *disassemble_fn;
}
int disassemble_buffer( disassembler_ftype disassemble_fn,
disassemble_info *info,
int* offset,
PDIS_INFO pDisInfo)
disassemble_info *info,
int* offset,
PDIS_INFO pDisInfo)
{
int i, j, size = 0;
int len = 0;
@ -136,7 +136,7 @@ int disassemble_buffer( disassembler_ftype disassemble_fn,
while ( *offset < info->buffer_length ) {
/* call the libopcodes disassembler */
memset(pDisInfo->disassemblyString, 0x00, MAX_DIS_STRING);
/* set the insn_info_valid bit to 0, as explained in BFD's
* include/dis-asm.h. The bit will then be set to tell us
* whether the decoder supports "extra" information about the
@ -147,7 +147,7 @@ int disassemble_buffer( disassembler_ftype disassemble_fn,
size = (*disassemble_fn)(info->buffer_vma + *offset, info);
/* -- analyze disassembled instruction here -- */
/* -- print any symbol names as labels here -- */
/* save off corresponding hex bytes */
for ( j= 0,i = 0; i < 8; i++, j+=3) {
if ( i < size ){
@ -155,7 +155,7 @@ int disassemble_buffer( disassembler_ftype disassemble_fn,
pDisInfo->bytesBufferBin[i] = info->buffer[*offset + i];
}
}
/* add the augmented information to our disassembly info struct */
pDisInfo->count = size;
pDisInfo->insn_info_valid = info->insn_info_valid;
@ -167,44 +167,44 @@ int disassemble_buffer( disassembler_ftype disassemble_fn,
strcat(&(pDisInfo->disassemblyString[0]), disassembled_buffer);
memset(disassembled_buffer, 0x00, BUFF_SIZE);
if(size != 0){
*offset += size; /* advance position in buffer */
goto END;
}
}
END:
END:
return size;
}
void processBuffer(unsigned char* buff,
int buff_len,
bfd_vma buff_vma,
disassembler_ftype disassemble_fn,
struct disassemble_info* DI)
int buff_len,
bfd_vma buff_vma,
disassembler_ftype disassemble_fn,
struct disassemble_info* DI)
{
int bytesConsumed = -1;
int offset = 0;
int numDisassemblies = 0;
int i;
DI->buffer = buff; /* buffer of bytes to disassemble */
DI->buffer_length = buff_len; /* size of buffer */
DI->buffer_vma = buff_vma; /* base RVA of buffer */
memset(disassemblyInfoBuffer, 0x00, sizeof(DIS_INFO)*MAX_NUM_ENTRIES);
while((buff_len - offset) > 0 && bytesConsumed != 0 && numDisassemblies < MAX_NUM_ENTRIES){
bytesConsumed = disassemble_buffer( disassemble_fn, DI, &offset, &(disassemblyInfoBuffer[numDisassemblies++]));
}
for (i = 0; i < numDisassemblies; i++) {
printf("%s\nInfo: %d,%d,%d,%d,%d\n", disassemblyInfoBuffer[i].disassemblyString,
disassemblyInfoBuffer[i].count,
disassemblyInfoBuffer[i].insn_info_valid,
disassemblyInfoBuffer[i].branch_delay_insns,
disassemblyInfoBuffer[i].data_size,
disassemblyInfoBuffer[i].insn_type);
printf("%s\nInfo: %d,%d,%d,%d,%d\n", disassemblyInfoBuffer[i].disassemblyString,
disassemblyInfoBuffer[i].count,
disassemblyInfoBuffer[i].insn_info_valid,
disassemblyInfoBuffer[i].branch_delay_insns,
disassemblyInfoBuffer[i].data_size,
disassemblyInfoBuffer[i].insn_type);
}
}
@ -224,7 +224,7 @@ int main(int argc, char* argv[]){
char elf_file_location[MAX_ELF_FILE_PATH_LEN];
char arch_str[256];
char mach_str[256];
if ( argc < 8) {
fprintf(stderr, "Usage: %s target-str, arch, mach, disassembly base-addr (for rel offsets instrs), full-path to Little and Big Elfs, big/little ascii-byte-string up to %d chars\n", argv[0], MAX_ASCII_CHAR_BYTE_STRING);
listSupportedArchMachTargets();
@ -247,16 +247,16 @@ int main(int argc, char* argv[]){
mach = 0x00000000;
arch = (enum bfd_architecture) 0x00;
offset = 0x00000000;
sscanf(argv[2], "%128s", arch_str);
sscanf(argv[3], "%18lX", &mach);
sscanf(argv[4], "%10X", &end);
sscanf(argv[5], "%18lX", &offset);
// if arch starts with 0x, then parse a number
// else lookup the string in the table to get the arch, ignore the mach
if (arch_str[0] == '0' && arch_str[1] == 'x') {
sscanf(arch_str, "%10X", &arch);
sscanf(arch_str, "%10X", &arch);
} else {
const char** archList = bfd_arch_list();
const bfd_arch_info_type* ait;
@ -271,17 +271,17 @@ int main(int argc, char* argv[]){
archList++;
}
if (ait == NULL) {
printf("Couldn't find arch %s\n", arch_str);
return(-1);
printf("Couldn't find arch %s\n", arch_str);
return(-1);
}
}
endian = (enum bfd_endian) end;
/* open a correct type of file to fill in most of the required data. */
// printf("Arch is: 0x%08X, Machine is: 0x%08lX Endian is: 0x%02X.\n", arch, mach, endian);
memset(elf_file_location, 0x00, MAX_ELF_FILE_PATH_LEN);
strncpy(elf_file_location, argv[6], MAX_ELF_FILE_PATH_LEN-sizeof(LITTLE_ELF_FILE)-2); // actual file name and nulls
@ -294,59 +294,66 @@ int main(int argc, char* argv[]){
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){
strcat(elf_file_location, BIG_ELF_FILE);
}
else {
strcat(elf_file_location, LITTLE_ELF_FILE);
}
bfd_init();
while (stdin_mode) {
//bfd_init();
// convert user input AsciiHex to Binary data for processing
char tmp[3];
unsigned int byteValue;
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
// read in the address
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);
}
//getchar();
// read in the ASCII hex string from stdin
if (fgets(byteStringBuffer, sizeof(byteStringBuffer), stdin)) {
//fprintf(stderr, "read: %s\n", byteStringBuffer);
// remove trailing newline
char *p = strchr(byteStringBuffer, '\n');
//Read in the rest of the input. There are two possible styles:
//"old": input is just the bytes to disassemble
//"new": input = bytes"*"<disassmbler_options>
//for compatibility reasons, handle both styles
if (fgets(bytesAndOptionsBuffer, sizeof(bytesAndOptionsBuffer), stdin)) {
char *p = strchr(bytesAndOptionsBuffer, '*');
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) {
fprintf(stderr, "Max ascii string size is %d you provided: %lu chars. Exiting.\n", BYTE_BUFFER_SIZE*2,
strlen(byteString));
fprintf(stderr, "Max ascii string size is %d you provided: %lu chars. Exiting.\n", BYTE_BUFFER_SIZE*2,
strlen(byteString));
exit(-1);
}
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++){
printf("0x%02X ", byteBuffer[j]);
}
*/
bfd_init( );
*/
//bfd_init( );
target = argv[1];
bfd_set_default_target(target);
@ -392,7 +399,7 @@ int main(int argc, char* argv[]){
bfdfile = bfd_openr(elf_file_location, target );
if ( ! bfdfile ) {
printf("Error opening BIG ELF file: %s\n", elf_file_location);
bfd_perror( "Error on bfdfile" );
bfd_perror( "Error on bfdfile" );
return(3);
}
}
@ -401,34 +408,37 @@ int main(int argc, char* argv[]){
if ( ! bfdfile ) {
printf("Error opening LITTLE ELF file: %s\n", elf_file_location);
// bfdfile = bfd_openr(elf_file_location, target );
bfd_perror( "Error on bfdfile" );
bfd_perror( "Error on bfdfile" );
return(3);
}
}
memset((void*) &DI, 0x00, sizeof(struct disassemble_info));
disassemble_fn = NULL;
// important set up!
//---------------------------------------
ai.arch = arch;
ai.mach = mach;
bfd_set_arch_info(bfdfile, &ai);
//---------------------------------------
/*
bfd_error_type err = bfd_get_error();
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);
/*
err = bfd_get_error();
printf("bfd_error_msg: %s.\n", bfd_errmsg(err));
*/
*/
if (disassemble_fn == NULL){
fprintf(stderr, "Error: disassemble_fn is NULL. Nothing I can do.\n");
exit(1);
@ -437,21 +447,25 @@ int main(int argc, char* argv[]){
/*
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");
*/
*/
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.
processBuffer(byteBuffer, size >> 1, offset, disassemble_fn, &DI); //
processBuffer(byteBuffer, size >> 1, offset, disassemble_fn, &DI); //
}
free((void*)bfdfile->xvec);
bfd_close(bfdfile);
printf("EOF\n");
fflush(stdout);
} // while loop on lines of stdin
return 0;
}

View File

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

View File

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

View File

@ -18,19 +18,23 @@ package ghidra.app.util.disassemble;
import java.io.*;
import java.util.*;
import org.apache.commons.lang3.StringUtils;
import org.jdom.*;
import org.jdom.input.SAXBuilder;
import generic.jar.ResourceFile;
import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.MemoryByteProvider;
import ghidra.framework.*;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressOutOfBoundsException;
import ghidra.program.model.lang.Language;
import ghidra.program.model.lang.LanguageID;
import ghidra.program.model.listing.CodeUnit;
import ghidra.program.model.listing.Program;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.MemBuffer;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.util.Msg;
import ghidra.util.xml.XmlUtilities;
import util.CollectionUtils;
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
private static final String READ_FROM_STDIN_PARAMETER = "stdin";
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 ENDING_STRING = "EOF";
private static final int NUM_BYTES = 32;
@ -48,6 +53,8 @@ public class GNUExternalDisassembler implements ExternalDisassembler {
private static final String GDIS_EXE =
Platform.CURRENT_PLATFORM.getOperatingSystem() == OperatingSystem.WINDOWS ? "gdis.exe"
: "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 File defaultGdisExecFile;
@ -82,6 +89,21 @@ public class GNUExternalDisassembler implements ExternalDisassembler {
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) {
List<String> externalNames = language.getLanguageDescription().getExternalNames("gnu");
if (externalNames != null && externalNames.size() > 1) {
@ -89,8 +111,9 @@ public class GNUExternalDisassembler implements ExternalDisassembler {
StringBuilder sb = new StringBuilder();
boolean prependSeparator = false;
for (String name : externalNames) {
if (prependSeparator)
if (prependSeparator) {
sb.append(", ");
}
sb.append(name);
prependSeparator = true;
}
@ -110,11 +133,17 @@ public class GNUExternalDisassembler implements ExternalDisassembler {
String machineId;
File gdisExecFile;
boolean usingDefault;
Register contextRegister;
Map<Long, String> valueToOptionString;
Map<Long, String> valueToDisplayPrefix;
Language lang;
String globalDisassemblerOptions;
GdisConfig(Language language, boolean isBigEndian) {
this.languageId = language.getLanguageID().toString();
this.isBigEndian = isBigEndian;
this.lang = language;
List<String> architectures = language.getLanguageDescription().getExternalNames("gnu");
//get first non-null
@ -143,12 +172,123 @@ public class GNUExternalDisassembler implements ExternalDisassembler {
gdisExecFile = defaultGdisExecFile;
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) {
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
public boolean equals(Object obj) {
if (!(obj instanceof GdisConfig)) {
@ -260,7 +400,7 @@ public class GNUExternalDisassembler implements ExternalDisassembler {
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,
@ -272,8 +412,8 @@ public class GNUExternalDisassembler implements ExternalDisassembler {
int blockSize = pow2(blockSizeFactor);
Address blockAddr = addr.getNewAddress(addr.getOffset() & -blockSize); // block
// aligned
// address
// aligned
// address
return getBlockDisassembly(program.getLanguage(), blockAddr, blockSizeFactor,
new MemoryByteProvider(program.getMemory(), blockAddr));
@ -301,7 +441,37 @@ public class GNUExternalDisassembler implements ExternalDisassembler {
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) {
return "(bad)";
@ -324,7 +494,7 @@ public class GNUExternalDisassembler implements ExternalDisassembler {
String address = "0x" + Long.toHexString(addressOffset);
List<GnuDisassembledInstruction> disassembly =
runDisassembler(gdisConfig, address, bytesString);
runDisassembler(gdisConfig, address, bytesString, EMPTY_DISASSEMBLER_OPTIONS);
if (disassembly == null || disassembly.isEmpty() || disassembly.get(0) == null) {
return "(bad)";
@ -332,14 +502,26 @@ public class GNUExternalDisassembler implements ExternalDisassembler {
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) {
String byteString = null;
for (byte thisByte : bytes) {
String thisByteString = Integer.toHexString(thisByte);
if (thisByteString.length() == 1)
if (thisByteString.length() == 1) {
thisByteString = "0" + thisByteString; // pad single digits
if (thisByteString.length() > 2)
}
if (thisByteString.length() > 2) {
thisByteString = thisByteString.substring(thisByteString.length() - 2);
}
// append this byte's hex string to the larger word length string
byteString = byteString + thisByteString;
}
@ -402,7 +584,7 @@ public class GNUExternalDisassembler implements ExternalDisassembler {
}
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
// 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 (!setupDisassembler(gdisConfig))
if (!setupDisassembler(gdisConfig)) {
return null;
}
outputWriter = new OutputStreamWriter(disassemblerProcess.getOutputStream());
@ -432,7 +615,14 @@ public class GNUExternalDisassembler implements ExternalDisassembler {
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 {
outputWriter.write(disassemblyRequest);
outputWriter.flush();

View File

@ -3,6 +3,7 @@ Module.manifest||GHIDRA||||END|
build.gradle||GHIDRA||||END|
data/languages/ARM.cspec||GHIDRA||||END|
data/languages/ARM.dwarf||GHIDRA||||END|
data/languages/ARM.gdis||GHIDRA||||END|
data/languages/ARM.ldefs||GHIDRA||||END|
data/languages/ARM.opinion||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="Visual Studio" spec="ARM_win.cspec" id="windows"/>
<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="DWARF.register.mapping.file" name="ARMneon.dwarf"/>
</language>
@ -31,6 +32,7 @@
<compiler name="default" spec="ARM.cspec" id="default"/>
<compiler name="Visual Studio" spec="ARM_win.cspec" id="windows"/>
<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="DWARF.register.mapping.file" name="ARMneon.dwarf"/>
</language>
@ -63,6 +65,7 @@
<description>Generic ARM/Thumb v8 big endian</description>
<compiler name="default" spec="ARM.cspec" id="default"/>
<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="DWARF.register.mapping.file" name="ARMneon.dwarf"/>
</language>
@ -96,6 +99,7 @@
<compiler name="default" spec="ARM.cspec" id="default"/>
<compiler name="Visual Studio" spec="ARM_win.cspec" id="windows"/>
<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="DWARF.register.mapping.file" name="ARMneon.dwarf"/>
</language>
@ -128,6 +132,7 @@
<description>Generic ARM/Thumb v7 big endian</description>
<compiler name="default" spec="ARM.cspec" id="default"/>
<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="DWARF.register.mapping.file" name="ARMneon.dwarf"/>
</language>
@ -174,6 +179,7 @@
<description>Generic ARM/Thumb v6 little endian</description>
<compiler name="default" spec="ARM_v45.cspec" id="default"/>
<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="DWARF.register.mapping.file" name="ARM.dwarf"/>
<!-- change DWARF register mapping to ARMneon.dwarf if VFPv2 is enabled -->
@ -192,6 +198,7 @@
<description>Generic ARM/Thumb v6 big endian</description>
<compiler name="default" spec="ARM_v45.cspec" id="default"/>
<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="DWARF.register.mapping.file" name="ARM.dwarf"/>
<!-- 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>
<compiler name="default" spec="ARM_v45.cspec" id="default"/>
<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="DWARF.register.mapping.file" name="ARM.dwarf"/>
</language>
@ -226,6 +234,7 @@
<description>Generic ARM/Thumb v5 big endian (T-variant)</description>
<compiler name="default" spec="ARM_v45.cspec" id="default"/>
<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="DWARF.register.mapping.file" name="ARM.dwarf"/>
</language>
@ -274,6 +283,7 @@
<description>Generic ARM/Thumb v4 little endian (T-variant)</description>
<compiler name="default" spec="ARM_v45.cspec" id="default"/>
<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="DWARF.register.mapping.file" name="ARM.dwarf"/>
</language>
@ -290,6 +300,7 @@
<description>Generic ARM/Thumb v4 big endian (T-variant)</description>
<compiler name="default" spec="ARM_v45.cspec" id="default"/>
<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="DWARF.register.mapping.file" name="ARM.dwarf"/>
</language>

View File

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

View File

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

View File

@ -58,6 +58,8 @@
<external_name tool="IDA-PRO" name="80486r"/>
<external_name tool="IDA-PRO" name="80586r"/>
<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 processor="x86"
endian="little"
@ -71,6 +73,8 @@
<description>Intel/AMD 16-bit x86 Protected Mode</description>
<compiler name="default" spec="x86-16.cspec" id="default"/>
<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 processor="x86"
endian="little"