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

@ -174,7 +174,7 @@ int disassemble_buffer( disassembler_ftype disassemble_fn,
}
}
END:
END:
return size;
}
@ -294,11 +294,6 @@ 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);
}
@ -306,44 +301,56 @@ int main(int argc, char* argv[]){
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) {
strncpy(byteStringBuffer,bytesAndOptionsBuffer,(int) (p - bytesAndOptionsBuffer));
strncpy(disassemblerOptions,p+1,sizeof(disassemblerOptions));
p = strchr(disassemblerOptions,'\n');
if (p){
*p = '\0';
}
//if (strcmp(byteStringBuffer, "EOF") == 0) {
//return 0; // terminate on EOF string
//}
} else {
}
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';
}
}
}
else {
fprintf(stderr, "exiting, no ASCII hex found\n");
return 0; // finished! #TODO
}
} else {
}
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));
@ -380,7 +387,7 @@ int main(int argc, char* argv[]){
}
*/
bfd_init( );
//bfd_init( );
target = argv[1];
bfd_set_default_target(target);
@ -422,6 +429,9 @@ int main(int argc, char* argv[]){
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);
/*
@ -438,7 +448,11 @@ 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); //

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,
@ -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"