mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
Candidate release of source code.
This commit is contained in:
parent
db81e6b3b0
commit
79d8f164f8
12449 changed files with 2800756 additions and 16 deletions
320
Ghidra/Features/Decompiler/src/decompile/cpp/printjava.cc
Normal file
320
Ghidra/Features/Decompiler/src/decompile/cpp/printjava.cc
Normal file
|
@ -0,0 +1,320 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "printjava.hh"
|
||||
#include "funcdata.hh"
|
||||
|
||||
OpToken PrintJava::instanceof = { "instanceof", 2, 60, true, OpToken::binary, 1, 0, (OpToken *)0 };
|
||||
|
||||
// Constructing this registers the capability
|
||||
PrintJavaCapability PrintJavaCapability::printJavaCapability;
|
||||
|
||||
PrintJavaCapability::PrintJavaCapability(void)
|
||||
|
||||
{
|
||||
name = "java-language";
|
||||
isdefault = false;
|
||||
}
|
||||
|
||||
PrintLanguage *PrintJavaCapability::buildLanguage(Architecture *glb)
|
||||
|
||||
{
|
||||
return new PrintJava(glb,name);
|
||||
}
|
||||
|
||||
PrintJava::PrintJava(Architecture *glb,const string &nm) : PrintC(glb,nm)
|
||||
|
||||
{
|
||||
option_NULL = true; // Automatically use 'null' token
|
||||
nullToken = "null"; // Java standard lower-case 'null'
|
||||
mods |= hide_thisparam; // turn on hiding of 'this' parameter
|
||||
if (castStrategy != (CastStrategy *)0)
|
||||
delete castStrategy;
|
||||
|
||||
castStrategy = new CastStrategyJava();
|
||||
}
|
||||
|
||||
/// Print a data-type up to the identifier, store off array sizes
|
||||
/// for printing after the identifier. Find the root type (the one with an identifier)
|
||||
/// and the count number of wrapping arrays.
|
||||
/// \param ct is the given data-type
|
||||
/// \param noident is \b true if no identifier will be pushed with this declaration
|
||||
void PrintJava::pushTypeStart(const Datatype *ct,bool noident)
|
||||
|
||||
{
|
||||
int4 arrayCount = 0;
|
||||
for(;;) {
|
||||
if (ct->getMetatype() == TYPE_PTR) {
|
||||
if (isArrayType(ct))
|
||||
arrayCount += 1;
|
||||
ct = ((TypePointer *)ct)->getPtrTo();
|
||||
}
|
||||
else if (ct->getName().size() != 0)
|
||||
break;
|
||||
else {
|
||||
ct = glb->types->getTypeVoid();
|
||||
break;
|
||||
}
|
||||
}
|
||||
OpToken *tok;
|
||||
|
||||
if (noident)
|
||||
tok = &type_expr_nospace;
|
||||
else
|
||||
tok = &type_expr_space;
|
||||
|
||||
pushOp(tok,(const PcodeOp *)0);
|
||||
for(int4 i=0;i<arrayCount;++i)
|
||||
pushOp(&subscript,(const PcodeOp *)0);
|
||||
|
||||
if (ct->getName().size()==0) { // Check for anonymous type
|
||||
// We could support a struct or enum declaration here
|
||||
string name = genericTypeName(ct);
|
||||
pushAtom(Atom(name,typetoken,EmitXml::type_color,ct));
|
||||
}
|
||||
else {
|
||||
pushAtom(Atom(ct->getName(),typetoken,EmitXml::type_color,ct));
|
||||
}
|
||||
for(int4 i=0;i<arrayCount;++i)
|
||||
pushAtom(Atom("",blanktoken,EmitXml::no_color)); // Fill in the blank array index
|
||||
}
|
||||
|
||||
void PrintJava::pushTypeEnd(const Datatype *ct)
|
||||
|
||||
{ // This routine doesn't have to do anything
|
||||
}
|
||||
|
||||
void PrintJava::adjustTypeOperators(void)
|
||||
|
||||
{
|
||||
TypeOp::selectJavaOperators(glb->inst,true);
|
||||
}
|
||||
|
||||
/// References to java array objects where the underlying element is a java primitive look like:
|
||||
/// - Pointer to int
|
||||
/// - Pointer to bool
|
||||
/// - Pointer to float
|
||||
///
|
||||
/// An array of java class objects is represented as a pointer to pointer data-type.
|
||||
/// \param ct is the given data-type
|
||||
/// \return \b true if the data-type references a java array object
|
||||
bool PrintJava::isArrayType(const Datatype *ct)
|
||||
|
||||
{
|
||||
if (ct->getMetatype() != TYPE_PTR) // Java arrays are always Ghidra pointer types
|
||||
return false;
|
||||
ct = ((TypePointer *)ct)->getPtrTo();
|
||||
switch(ct->getMetatype()) {
|
||||
case TYPE_UINT: // Pointer to unsigned is placeholder for class reference, not an array
|
||||
if (ct->isCharPrint())
|
||||
return true;
|
||||
break;
|
||||
case TYPE_INT:
|
||||
case TYPE_BOOL:
|
||||
case TYPE_FLOAT: // Pointer to primitive type is an array
|
||||
case TYPE_PTR: // Pointer to class reference is an array
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Assuming the given Varnode is a dereferenced pointer, determine whether
|
||||
/// it needs to be represented using '[0]' syntax.
|
||||
/// \param vn is the given Varnode
|
||||
/// \return \b true if '[0]' syntax is required
|
||||
bool PrintJava::needZeroArray(const Varnode *vn)
|
||||
|
||||
{
|
||||
if (!isArrayType(vn->getType()))
|
||||
return false;
|
||||
if (vn->isExplicit()) return true;
|
||||
if (!vn->isWritten()) return true;
|
||||
OpCode opc = vn->getDef()->code();
|
||||
if ((opc == CPUI_PTRADD)||(opc == CPUI_PTRSUB)||(opc == CPUI_CPOOLREF))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void PrintJava::printUnicode(ostream &s,int4 onechar) const
|
||||
|
||||
{
|
||||
if (unicodeNeedsEscape(onechar)) {
|
||||
switch(onechar) { // Special escape characters
|
||||
case 0:
|
||||
s << "\\0";
|
||||
return;
|
||||
case 8:
|
||||
s << "\\b";
|
||||
return;
|
||||
case 9:
|
||||
s << "\\t";
|
||||
return;
|
||||
case 10:
|
||||
s << "\\n";
|
||||
return;
|
||||
case 12:
|
||||
s << "\\f";
|
||||
return;
|
||||
case 13:
|
||||
s << "\\r";
|
||||
return;
|
||||
case 92:
|
||||
s << "\\\\";
|
||||
return;
|
||||
case '"':
|
||||
s << "\\\"";
|
||||
return;
|
||||
case '\'':
|
||||
s << "\\\'";
|
||||
return;
|
||||
}
|
||||
// Generic unicode escape
|
||||
if (onechar < 65536) {
|
||||
s << "\\ux" << setfill('0') << setw(4) << hex << onechar;
|
||||
}
|
||||
else
|
||||
s << "\\ux" << setfill('0') << setw(8) << hex << onechar;
|
||||
return;
|
||||
}
|
||||
writeUtf8(s, onechar); // Emit normally
|
||||
}
|
||||
|
||||
void PrintJava::opLoad(const PcodeOp *op)
|
||||
|
||||
{
|
||||
uint4 m = mods | print_load_value;
|
||||
bool printArrayRef = needZeroArray(op->getIn(1));
|
||||
if (printArrayRef)
|
||||
pushOp(&subscript,op);
|
||||
pushVnImplied(op->getIn(1),op,m);
|
||||
if (printArrayRef)
|
||||
push_integer(0,4,false,(Varnode *)0,op);
|
||||
}
|
||||
|
||||
void PrintJava::opStore(const PcodeOp *op)
|
||||
|
||||
{
|
||||
uint4 m = mods | print_store_value; // Inform sub-tree that we are storing
|
||||
pushOp(&assignment,op); // This is an assignment
|
||||
if (needZeroArray(op->getIn(1))) {
|
||||
pushOp(&subscript,op);
|
||||
pushVnImplied(op->getIn(1),op,m);
|
||||
push_integer(0,4,false,(Varnode *)0,op);
|
||||
pushVnImplied(op->getIn(2),op,mods);
|
||||
}
|
||||
else {
|
||||
// implied vn's pushed on in reverse order for efficiency
|
||||
// see PrintLanguage::pushVnImplied
|
||||
pushVnImplied(op->getIn(2),op,mods);
|
||||
pushVnImplied(op->getIn(1),op,m);
|
||||
}
|
||||
}
|
||||
|
||||
void PrintJava::opCallind(const PcodeOp *op)
|
||||
|
||||
{
|
||||
pushOp(&function_call,op);
|
||||
// implied vn's pushed on in reverse order for efficiency
|
||||
// see PrintLanguage::pushVnImplied
|
||||
int4 startparam = isSet(hide_thisparam) && op->hasThisPointer() ? 2 : 1;
|
||||
if (op->numInput()>startparam + 1) { // Multiple parameters
|
||||
pushVnImplied(op->getIn(0),op,mods);
|
||||
for(int4 i=startparam;i<op->numInput()-1;++i)
|
||||
pushOp(&comma,op);
|
||||
for(int4 i=op->numInput()-1;i>=startparam;--i)
|
||||
pushVnImplied(op->getIn(i),op,mods);
|
||||
}
|
||||
else if (op->numInput()==startparam + 1) { // One parameter
|
||||
pushVnImplied(op->getIn(startparam),op,mods);
|
||||
pushVnImplied(op->getIn(0),op,mods);
|
||||
}
|
||||
else { // A void function
|
||||
pushVnImplied(op->getIn(0),op,mods);
|
||||
pushAtom(Atom("",blanktoken,EmitXml::no_color));
|
||||
}
|
||||
}
|
||||
|
||||
void PrintJava::opCpoolRefOp(const PcodeOp *op)
|
||||
|
||||
{
|
||||
const Varnode *outvn = op->getOut();
|
||||
const Varnode *vn0 = op->getIn(0);
|
||||
vector<uintb> refs;
|
||||
for(int4 i=1;i<op->numInput();++i)
|
||||
refs.push_back(op->getIn(i)->getOffset());
|
||||
const CPoolRecord *rec = glb->cpool->getRecord(refs);
|
||||
if (rec == (const CPoolRecord *)0) {
|
||||
pushAtom(Atom("UNKNOWNREF",syntax,EmitXml::const_color,op,outvn));
|
||||
}
|
||||
else {
|
||||
switch(rec->getTag()) {
|
||||
case CPoolRecord::string_literal:
|
||||
{
|
||||
ostringstream str;
|
||||
int4 len = rec->getByteDataLength();
|
||||
if (len > 2048)
|
||||
len = 2048;
|
||||
str << '\"';
|
||||
escapeCharacterData(str,rec->getByteData(),len,1,false);
|
||||
if (len == rec->getByteDataLength())
|
||||
str << '\"';
|
||||
else {
|
||||
str << "...\"";
|
||||
}
|
||||
pushAtom(Atom(str.str(),vartoken,EmitXml::const_color,op,outvn));
|
||||
break;
|
||||
}
|
||||
case CPoolRecord::class_reference:
|
||||
pushAtom(Atom(rec->getToken(),vartoken,EmitXml::type_color,op,outvn));
|
||||
break;
|
||||
case CPoolRecord::instance_of:
|
||||
{
|
||||
Datatype *dt = rec->getType();
|
||||
while(dt->getMetatype() == TYPE_PTR) {
|
||||
dt = ((TypePointer *)dt)->getPtrTo();
|
||||
}
|
||||
pushOp(&instanceof,op);
|
||||
pushVnImplied(vn0,op,mods);
|
||||
pushAtom(Atom(dt->getName(),syntax,EmitXml::type_color,op,outvn));
|
||||
break;
|
||||
}
|
||||
case CPoolRecord::primitive: // Should be eliminated
|
||||
case CPoolRecord::pointer_method:
|
||||
case CPoolRecord::pointer_field:
|
||||
case CPoolRecord::array_length:
|
||||
case CPoolRecord::check_cast:
|
||||
default:
|
||||
{
|
||||
Datatype *ct = rec->getType();
|
||||
EmitXml::syntax_highlight color = EmitXml::var_color;
|
||||
if (ct->getMetatype() == TYPE_PTR) {
|
||||
ct = ((TypePointer *)ct)->getPtrTo();
|
||||
if (ct->getMetatype() == TYPE_CODE)
|
||||
color = EmitXml::funcname_color;
|
||||
}
|
||||
if (vn0->isConstant()) { // If this is NOT relative to an object reference
|
||||
pushAtom(Atom(rec->getToken(),vartoken,color,op,outvn));
|
||||
}
|
||||
else {
|
||||
pushOp(&object_member,op);
|
||||
pushVnImplied(vn0,op,mods);
|
||||
pushAtom(Atom(rec->getToken(),syntax,color,op,outvn));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue