mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
Converted StringManager to use vectors
This commit is contained in:
parent
0eb48e441f
commit
1529e635fc
11 changed files with 161 additions and 111 deletions
|
@ -19,6 +19,7 @@
|
||||||
#include "ghidra_translate.hh"
|
#include "ghidra_translate.hh"
|
||||||
#include "typegrp_ghidra.hh"
|
#include "typegrp_ghidra.hh"
|
||||||
#include "comment_ghidra.hh"
|
#include "comment_ghidra.hh"
|
||||||
|
#include "string_ghidra.hh"
|
||||||
#include "cpool_ghidra.hh"
|
#include "cpool_ghidra.hh"
|
||||||
#include "inject_ghidra.hh"
|
#include "inject_ghidra.hh"
|
||||||
|
|
||||||
|
@ -346,6 +347,12 @@ void ArchitectureGhidra::buildCommentDB(DocumentStorage &store)
|
||||||
commentdb = new CommentDatabaseGhidra(this);
|
commentdb = new CommentDatabaseGhidra(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ArchitectureGhidra::buildStringManager(DocumentStorage &store)
|
||||||
|
|
||||||
|
{
|
||||||
|
stringManager = new GhidraStringManager(this,2048);
|
||||||
|
}
|
||||||
|
|
||||||
void ArchitectureGhidra::buildConstantPool(DocumentStorage &store)
|
void ArchitectureGhidra::buildConstantPool(DocumentStorage &store)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -615,7 +622,7 @@ void ArchitectureGhidra::getBytes(uint1 *buf,int4 size,const Address &inaddr)
|
||||||
readResponseEnd(sin);
|
readResponseEnd(sin);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint4 ArchitectureGhidra::getStringData(uint1 *buf,const Address &addr,Datatype *ct,int4 maxBytes)
|
void ArchitectureGhidra::getStringData(vector<uint1> &buffer,const Address &addr,Datatype *ct,int4 maxBytes)
|
||||||
|
|
||||||
{
|
{
|
||||||
sout.write("\000\000\001\004",4);
|
sout.write("\000\000\001\004",4);
|
||||||
|
@ -633,32 +640,28 @@ uint4 ArchitectureGhidra::getStringData(uint1 *buf,const Address &addr,Datatype
|
||||||
|
|
||||||
readToResponse(sin);
|
readToResponse(sin);
|
||||||
int4 type = readToAnyBurst(sin);
|
int4 type = readToAnyBurst(sin);
|
||||||
uint4 size = 0;
|
|
||||||
if (type == 12) {
|
if (type == 12) {
|
||||||
int4 c = sin.get();
|
int4 c = sin.get();
|
||||||
size ^= (c-0x20);
|
uint4 size = (c-0x20);
|
||||||
c = sin.get();
|
c = sin.get();
|
||||||
size ^= ((c-0x20)<<6);
|
size ^= ((c-0x20)<<6);
|
||||||
|
buffer.reserve(size);
|
||||||
uint1 *dblbuf = new uint1[size * 2];
|
uint1 *dblbuf = new uint1[size * 2];
|
||||||
sin.read((char *)dblbuf,size*2);
|
sin.read((char *)dblbuf,size*2);
|
||||||
for (int4 i=0; i < size; i++) {
|
for (int4 i=0; i < size; i++) {
|
||||||
buf[i] = ((dblbuf[i*2]-'A') << 4) | (dblbuf[i*2 + 1]-'A');
|
buffer.push_back(((dblbuf[i*2]-'A') << 4) | (dblbuf[i*2 + 1]-'A'));
|
||||||
}
|
}
|
||||||
delete [] dblbuf;
|
delete [] dblbuf;
|
||||||
|
type = readToAnyBurst(sin);
|
||||||
|
if (type != 13)
|
||||||
|
throw JavaError("alignment","Expecting byte alignment end");
|
||||||
|
type = readToAnyBurst(sin);
|
||||||
}
|
}
|
||||||
else if ((type&1)==1) {
|
if ((type&1)==1) {
|
||||||
ostringstream errmsg;
|
// Leave the buffer empty
|
||||||
errmsg << "GHIDRA has no string in the loadimage at " << addr.getShortcut();
|
|
||||||
addr.printRaw(errmsg);
|
|
||||||
throw DataUnavailError(errmsg.str());
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw JavaError("alignment","Expecting bytes or end of query response");
|
throw JavaError("alignment","Expecting end of query response");
|
||||||
type = readToAnyBurst(sin);
|
|
||||||
if (type != 13)
|
|
||||||
throw JavaError("alignment","Expecting byte alignment end");
|
|
||||||
readResponseEnd(sin);
|
|
||||||
return size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Retrieve p-code to inject for a specific context
|
/// \brief Retrieve p-code to inject for a specific context
|
||||||
|
|
|
@ -74,6 +74,7 @@ class ArchitectureGhidra : public Architecture {
|
||||||
virtual PcodeInjectLibrary *buildPcodeInjectLibrary(void);
|
virtual PcodeInjectLibrary *buildPcodeInjectLibrary(void);
|
||||||
virtual void buildTypegrp(DocumentStorage &store);
|
virtual void buildTypegrp(DocumentStorage &store);
|
||||||
virtual void buildCommentDB(DocumentStorage &store);
|
virtual void buildCommentDB(DocumentStorage &store);
|
||||||
|
virtual void buildStringManager(DocumentStorage &store);
|
||||||
virtual void buildConstantPool(DocumentStorage &store);
|
virtual void buildConstantPool(DocumentStorage &store);
|
||||||
virtual void buildContext(DocumentStorage &store);
|
virtual void buildContext(DocumentStorage &store);
|
||||||
virtual void buildSpecFile(DocumentStorage &store);
|
virtual void buildSpecFile(DocumentStorage &store);
|
||||||
|
@ -124,7 +125,7 @@ public:
|
||||||
|
|
||||||
bool getSendParamMeasures(void) const { return sendParamMeasures; } ///< Get the current setting for emitting parameter info
|
bool getSendParamMeasures(void) const { return sendParamMeasures; } ///< Get the current setting for emitting parameter info
|
||||||
|
|
||||||
virtual uint4 getStringData(uint1 *buf,const Address &addr,Datatype *ct,int4 maxBytes);
|
virtual void getStringData(vector<uint1> &buffer,const Address &addr,Datatype *ct,int4 maxBytes);
|
||||||
virtual void printMessage(const string &message) const;
|
virtual void printMessage(const string &message) const;
|
||||||
|
|
||||||
static void segvHandler(int4 sig); ///< Handler for a segment violation (SIGSEGV) signal
|
static void segvHandler(int4 sig); ///< Handler for a segment violation (SIGSEGV) signal
|
||||||
|
|
|
@ -127,6 +127,7 @@ void IfaceDecompCapability::registerCommands(IfaceStatus *status)
|
||||||
status->registerCom(new IfcCallFixup(),"fixup","call");
|
status->registerCom(new IfcCallFixup(),"fixup","call");
|
||||||
status->registerCom(new IfcCallOtherFixup(),"fixup","callother");
|
status->registerCom(new IfcCallOtherFixup(),"fixup","callother");
|
||||||
status->registerCom(new IfcVolatile(),"volatile");
|
status->registerCom(new IfcVolatile(),"volatile");
|
||||||
|
status->registerCom(new IfcReadonly(),"readonly");
|
||||||
status->registerCom(new IfcPreferSplit(),"prefersplit");
|
status->registerCom(new IfcPreferSplit(),"prefersplit");
|
||||||
status->registerCom(new IfcStructureBlocks(),"structure","blocks");
|
status->registerCom(new IfcStructureBlocks(),"structure","blocks");
|
||||||
status->registerCom(new IfcAnalyzeRange(), "analyze","range");
|
status->registerCom(new IfcAnalyzeRange(), "analyze","range");
|
||||||
|
@ -2304,6 +2305,22 @@ void IfcVolatile::execute(istream &s)
|
||||||
*status->optr << "Successfully marked range as volatile" << endl;
|
*status->optr << "Successfully marked range as volatile" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IfcReadonly::execute(istream &s)
|
||||||
|
|
||||||
|
{
|
||||||
|
int4 size = 0;
|
||||||
|
if (dcp->conf == (Architecture *)0)
|
||||||
|
throw IfaceExecutionError("No load image present");
|
||||||
|
Address addr = parse_machaddr(s,size,*dcp->conf->types); // Read required address
|
||||||
|
|
||||||
|
if (size == 0)
|
||||||
|
throw IfaceExecutionError("Must specify a size");
|
||||||
|
Range range( addr.getSpace(), addr.getOffset(), addr.getOffset() + (size-1));
|
||||||
|
dcp->conf->symboltab->setPropertyRange(Varnode::readonly,range);
|
||||||
|
|
||||||
|
*status->optr << "Successfully marked range as readonly" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
void IfcPreferSplit::execute(istream &s)
|
void IfcPreferSplit::execute(istream &s)
|
||||||
|
|
||||||
{ // Mark a particular storage location as something we would prefer to split
|
{ // Mark a particular storage location as something we would prefer to split
|
||||||
|
|
|
@ -531,6 +531,11 @@ public:
|
||||||
virtual void execute(istream &s);
|
virtual void execute(istream &s);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class IfcReadonly : public IfaceDecompCommand {
|
||||||
|
public:
|
||||||
|
virtual void execute(istream &s);
|
||||||
|
};
|
||||||
|
|
||||||
class IfcPreferSplit : public IfaceDecompCommand {
|
class IfcPreferSplit : public IfaceDecompCommand {
|
||||||
public:
|
public:
|
||||||
virtual void execute(istream &s);
|
virtual void execute(istream &s);
|
||||||
|
|
|
@ -1216,20 +1216,23 @@ bool PrintC::doEmitWideCharPrefix(void) const
|
||||||
bool PrintC::printCharacterConstant(ostream &s,const Address &addr,Datatype *charType) const
|
bool PrintC::printCharacterConstant(ostream &s,const Address &addr,Datatype *charType) const
|
||||||
|
|
||||||
{
|
{
|
||||||
const uint1 *buffer;
|
|
||||||
StringManager *manager = glb->stringManager;
|
StringManager *manager = glb->stringManager;
|
||||||
try {
|
|
||||||
buffer = manager->getStringData(addr, charType);
|
// Retrieve UTF8 version of string
|
||||||
} catch(DataUnavailError &err) {
|
const vector<uint1> &buffer(manager->getStringData(addr, charType));
|
||||||
|
if (buffer.empty())
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
if (doEmitWideCharPrefix() && charType->getSize() > 1)
|
if (doEmitWideCharPrefix() && charType->getSize() > 1)
|
||||||
s << 'L'; // Print symbol indicating wide character
|
s << 'L'; // Print symbol indicating wide character
|
||||||
s << '"';
|
s << '"';
|
||||||
if (!escapeCharacterData(s,buffer,manager->getMaximumBytes(),charType->getSize(),glb->translate->isBigEndian()))
|
if (!escapeCharacterData(s,buffer.data(),buffer.size(),1,glb->translate->isBigEndian()))
|
||||||
s << "...\" /* TRUNCATED STRING LITERAL */";
|
s << "...\" /* TRUNCATED STRING LITERAL */";
|
||||||
else
|
else {
|
||||||
s << '"';
|
if (buffer.size() > manager->getMaximumBytes())
|
||||||
|
s << "...\" /* TRUNCATED STRING LITERAL */";
|
||||||
|
else
|
||||||
|
s << '"';
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
#include "ghidra_string.hh"
|
#include "string_ghidra.hh"
|
||||||
|
|
||||||
GhidraStringManager::GhidraStringManager(ArchitectureGhidra *g,int4 max)
|
GhidraStringManager::GhidraStringManager(ArchitectureGhidra *g,int4 max)
|
||||||
: StringManager(max)
|
: StringManager(max)
|
||||||
|
@ -28,14 +28,15 @@ GhidraStringManager::~GhidraStringManager(void)
|
||||||
delete [] testBuffer;
|
delete [] testBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint1 *GhidraStringManager::getStringData(const Address &addr,Datatype *charType)
|
const vector<uint1> &GhidraStringManager::getStringData(const Address &addr,Datatype *charType)
|
||||||
|
|
||||||
{
|
{
|
||||||
map<Address,const uint1 *>::iterator iter;
|
map<Address,vector<uint1> >::iterator iter;
|
||||||
iter = stringMap.find(addr);
|
iter = stringMap.find(addr);
|
||||||
if (iter != stringMap.end())
|
if (iter != stringMap.end())
|
||||||
return (*iter).second;
|
return (*iter).second;
|
||||||
|
|
||||||
int4 size = glb->getStringData(testBuffer, addr, charType, maximumBytes);
|
vector<uint1> &buffer(stringMap[addr]);
|
||||||
return mapBuffer(addr, testBuffer, size);
|
glb->getStringData(buffer, addr, charType, maximumBytes);
|
||||||
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ class GhidraStringManager : public StringManager {
|
||||||
public:
|
public:
|
||||||
GhidraStringManager(ArchitectureGhidra *g,int4 max); ///< Constructor
|
GhidraStringManager(ArchitectureGhidra *g,int4 max); ///< Constructor
|
||||||
virtual ~GhidraStringManager(void);
|
virtual ~GhidraStringManager(void);
|
||||||
virtual const uint1 *getStringData(const Address &addr,Datatype *charType);
|
virtual const vector<uint1> &getStringData(const Address &addr,Datatype *charType);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -16,21 +16,6 @@
|
||||||
#include "stringmanage.hh"
|
#include "stringmanage.hh"
|
||||||
#include "architecture.hh"
|
#include "architecture.hh"
|
||||||
|
|
||||||
/// Before calling, we must check that there is no other buffer stored at the address.
|
|
||||||
/// \param addr is the Address to store the buffer at
|
|
||||||
/// \param buf is the buffer to be copied into storage
|
|
||||||
/// \param size is the number of bytes in the buffer
|
|
||||||
/// \return the new permanent copy of the buffer
|
|
||||||
const uint1 *StringManager::mapBuffer(const Address &addr,const uint1 *buf,int4 size)
|
|
||||||
|
|
||||||
{
|
|
||||||
uint1 *storeBuf = new uint1[size + 1];
|
|
||||||
stringMap[addr] = storeBuf;
|
|
||||||
memcpy(storeBuf,buf,size);
|
|
||||||
storeBuf[size] = 0;
|
|
||||||
return storeBuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \param max is the maximum number of bytes to allow in a decoded string
|
/// \param max is the maximum number of bytes to allow in a decoded string
|
||||||
StringManager::StringManager(int4 max)
|
StringManager::StringManager(int4 max)
|
||||||
|
|
||||||
|
@ -44,16 +29,6 @@ StringManager::~StringManager(void)
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void StringManager::clear(void)
|
|
||||||
|
|
||||||
{
|
|
||||||
map<Address,const uint1 *>::iterator iter;
|
|
||||||
|
|
||||||
for(iter=stringMap.begin();iter!=stringMap.end();++iter) {
|
|
||||||
delete [] (*iter).second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Encode the given unicode codepoint as UTF8 (1, 2, 3, or 4 bytes) and
|
/// Encode the given unicode codepoint as UTF8 (1, 2, 3, or 4 bytes) and
|
||||||
/// write the bytes to the stream.
|
/// write the bytes to the stream.
|
||||||
/// \param s is the output stream
|
/// \param s is the output stream
|
||||||
|
@ -103,14 +78,8 @@ void StringManager::writeUtf8(ostream &s,int4 codepoint)
|
||||||
bool StringManager::isString(const Address &addr,Datatype *charType)
|
bool StringManager::isString(const Address &addr,Datatype *charType)
|
||||||
|
|
||||||
{
|
{
|
||||||
const uint1 *buffer = (const uint1 *)0;
|
const vector<uint1> &buffer(getStringData(addr,charType));
|
||||||
try {
|
return !buffer.empty();
|
||||||
buffer = getStringData(addr,charType);
|
|
||||||
}
|
|
||||||
catch(DataUnavailError &err) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return (buffer != (const uint1 *)0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write \<stringmanage> tag, with \<string> sub-tags.
|
/// Write \<stringmanage> tag, with \<string> sub-tags.
|
||||||
|
@ -120,15 +89,14 @@ void StringManager::saveXml(ostream &s) const
|
||||||
{
|
{
|
||||||
s << "<stringmanage>\n";
|
s << "<stringmanage>\n";
|
||||||
|
|
||||||
map<Address,const uint1 *>::const_iterator iter1;
|
map<Address,vector<uint1> >::const_iterator iter1;
|
||||||
for(iter1=stringMap.begin();iter1!=stringMap.end();++iter1) {
|
for(iter1=stringMap.begin();iter1!=stringMap.end();++iter1) {
|
||||||
s << "<string>\n";
|
s << "<string>\n";
|
||||||
(*iter1).first.saveXml(s);
|
(*iter1).first.saveXml(s);
|
||||||
const uint1 *buf = (*iter1).second;
|
const vector<uint1> &vec( (*iter1).second );
|
||||||
s << " <bytes>\n" << setfill('0');
|
s << " <bytes>\n" << setfill('0');
|
||||||
for(int4 i=0;;++i) {
|
for(int4 i=0;vec.size();++i) {
|
||||||
if (buf[i] == 0) break;
|
s << hex << setw(2) << (int4)vec[i];
|
||||||
s << hex << setw(2) << (int4)buf[i];
|
|
||||||
if (i%20 == 19)
|
if (i%20 == 19)
|
||||||
s << "\n ";
|
s << "\n ";
|
||||||
}
|
}
|
||||||
|
@ -148,7 +116,7 @@ void StringManager::restoreXml(const Element *el,const AddrSpaceManager *m)
|
||||||
iter = list.begin();
|
iter = list.begin();
|
||||||
Address addr = Address::restoreXml(*iter, m);
|
Address addr = Address::restoreXml(*iter, m);
|
||||||
++iter;
|
++iter;
|
||||||
vector<uint1> vec;
|
vector<uint1> &vec(stringMap[addr]);
|
||||||
istringstream is((*iter)->getContent());
|
istringstream is((*iter)->getContent());
|
||||||
int4 val;
|
int4 val;
|
||||||
char c1, c2;
|
char c1, c2;
|
||||||
|
@ -174,7 +142,6 @@ void StringManager::restoreXml(const Element *el,const AddrSpaceManager *m)
|
||||||
c1 = is.get();
|
c1 = is.get();
|
||||||
c2 = is.get();
|
c2 = is.get();
|
||||||
}
|
}
|
||||||
mapBuffer(addr,vec.data(),vec.size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \param buffer is the byte buffer
|
/// \param buffer is the byte buffer
|
||||||
|
@ -300,49 +267,61 @@ StringManagerUnicode::~StringManagerUnicode(void)
|
||||||
delete [] testBuffer;
|
delete [] testBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint1 *StringManagerUnicode::getStringData(const Address &addr,Datatype *charType)
|
const vector<uint1> &StringManagerUnicode::getStringData(const Address &addr,Datatype *charType)
|
||||||
|
|
||||||
{
|
{
|
||||||
map<Address,const uint1 *>::iterator iter;
|
map<Address,vector<uint1> >::iterator iter;
|
||||||
iter = stringMap.find(addr);
|
iter = stringMap.find(addr);
|
||||||
if (iter != stringMap.end())
|
if (iter != stringMap.end())
|
||||||
return (*iter).second;
|
return (*iter).second;
|
||||||
|
|
||||||
|
vector<uint1> &vec(stringMap[addr]); // Allocate (initially empty) byte vector
|
||||||
|
|
||||||
int4 curBufferSize = 0;
|
int4 curBufferSize = 0;
|
||||||
int4 charsize = charType->getSize();
|
int4 charsize = charType->getSize();
|
||||||
bool foundTerminator = false;
|
bool foundTerminator = false;
|
||||||
|
|
||||||
do {
|
try {
|
||||||
int4 amount = 32; // Grab 32 bytes of image at a time
|
do {
|
||||||
uint4 newBufferSize = curBufferSize + amount;
|
int4 amount = 32; // Grab 32 bytes of image at a time
|
||||||
if (newBufferSize > maximumBytes) {
|
uint4 newBufferSize = curBufferSize + amount;
|
||||||
newBufferSize = maximumBytes;
|
if (newBufferSize > maximumBytes) {
|
||||||
amount = newBufferSize - curBufferSize;
|
newBufferSize = maximumBytes;
|
||||||
if (amount == 0) break;
|
amount = newBufferSize - curBufferSize;
|
||||||
}
|
if (amount == 0)
|
||||||
glb->loader->loadFill(testBuffer+curBufferSize,amount,addr + curBufferSize);
|
break;
|
||||||
foundTerminator = hasCharTerminator(testBuffer+curBufferSize,amount,charsize);
|
}
|
||||||
curBufferSize = newBufferSize;
|
glb->loader->loadFill(testBuffer + curBufferSize, amount,
|
||||||
} while (!foundTerminator);
|
addr + curBufferSize);
|
||||||
|
foundTerminator = hasCharTerminator(testBuffer + curBufferSize, amount,
|
||||||
|
charsize);
|
||||||
|
curBufferSize = newBufferSize;
|
||||||
|
} while (!foundTerminator);
|
||||||
|
} catch (DataUnavailError &err) {
|
||||||
|
return vec; // Return the empty buffer
|
||||||
|
}
|
||||||
|
|
||||||
const uint1 *resBuffer;
|
|
||||||
if (charsize == 1) {
|
if (charsize == 1) {
|
||||||
if (!isCharacterConstant(testBuffer,curBufferSize,charsize))
|
if (!isCharacterConstant(testBuffer,curBufferSize,charsize))
|
||||||
return (const uint1 *)0;
|
return vec; // Return the empty buffer
|
||||||
resBuffer = mapBuffer(addr,testBuffer,curBufferSize);
|
vec.reserve(curBufferSize);
|
||||||
|
vec.assign(testBuffer,testBuffer+curBufferSize);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// We need to translate to UTF8
|
// We need to translate to UTF8
|
||||||
ostringstream s;
|
ostringstream s;
|
||||||
if (!writeUnicode(s, testBuffer, curBufferSize, charsize))
|
if (!writeUnicode(s, testBuffer, curBufferSize, charsize))
|
||||||
return (const uint1 *)0;
|
return vec; // Return the empty buffer
|
||||||
string resString = s.str();
|
string resString = s.str();
|
||||||
int4 newSize = resString.size();
|
int4 newSize = resString.size();
|
||||||
if (newSize > maximumBytes)
|
if (newSize > maximumBytes)
|
||||||
newSize = maximumBytes;
|
newSize = maximumBytes;
|
||||||
resBuffer = mapBuffer(addr,(const uint1 *)resString.c_str(),newSize);
|
vector<uint1> &vec(stringMap[addr]);
|
||||||
|
vec.reserve(newSize);
|
||||||
|
const uint1 *ptr = (const uint1 *)resString.c_str();
|
||||||
|
vec.assign(ptr,ptr+newSize);
|
||||||
}
|
}
|
||||||
return resBuffer;
|
return vec;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If the string is encoded in UTF8 or ASCII, we get (on average) a bit of check
|
/// If the string is encoded in UTF8 or ASCII, we get (on average) a bit of check
|
||||||
|
|
|
@ -30,27 +30,25 @@ class Architecture;
|
||||||
/// Stores the decoded string until its needed for presentation.
|
/// Stores the decoded string until its needed for presentation.
|
||||||
class StringManager {
|
class StringManager {
|
||||||
protected:
|
protected:
|
||||||
map<Address,const uint1 *> stringMap; ///< Map from address to string (in UTF8 format)
|
map<Address,vector<uint1> > stringMap; ///< Map from address to string (in UTF8 format)
|
||||||
int4 maximumBytes; ///< Maximum bytes (in UTF8 encoding) allowed
|
int4 maximumBytes; ///< Maximum bytes (in UTF8 encoding) allowed
|
||||||
|
|
||||||
const uint1 *mapBuffer(const Address &addr,const uint1 *buf,int4 size); ///< Move a decoded buffer into storage
|
|
||||||
public:
|
public:
|
||||||
StringManager(int4 max); ///< Constructor
|
StringManager(int4 max); ///< Constructor
|
||||||
virtual ~StringManager(void); ///< Destructor
|
virtual ~StringManager(void); ///< Destructor
|
||||||
|
|
||||||
int4 getMaximumBytes(void) const { return maximumBytes; } ///< Return the maximum bytes allowed in a string decoding
|
int4 getMaximumBytes(void) const { return maximumBytes; } ///< Return the maximum bytes allowed in a string decoding
|
||||||
void clear(void); ///< Clear out any cached strings
|
void clear(void) { stringMap.clear(); } ///< Clear out any cached strings
|
||||||
|
|
||||||
bool isString(const Address &addr,Datatype *charType); // Determine if data at the given address is a string
|
bool isString(const Address &addr,Datatype *charType); // Determine if data at the given address is a string
|
||||||
|
|
||||||
/// \brief Retrieve string data at the given address as a UTF8 byte array
|
/// \brief Retrieve string data at the given address as a UTF8 byte array
|
||||||
///
|
///
|
||||||
/// If the address does not represent string data, null is returned. Otherwise,
|
/// If the address does not represent string data, a zero length vector is returned. Otherwise,
|
||||||
/// the string data is fetched, converted to a UTF8 encoding, cached and returned.
|
/// the string data is fetched, converted to a UTF8 encoding, cached and returned.
|
||||||
/// \param addr is the given address
|
/// \param addr is the given address
|
||||||
/// \param charType is a character data-type indicating the encoding
|
/// \param charType is a character data-type indicating the encoding
|
||||||
/// \return the byte array of UTF8 data (or null)
|
/// \return the byte array of UTF8 data
|
||||||
virtual const uint1 *getStringData(const Address &addr,Datatype *charType)=0;
|
virtual const vector<uint1> &getStringData(const Address &addr,Datatype *charType)=0;
|
||||||
|
|
||||||
void saveXml(ostream &s) const; ///< Save cached strings to a stream as XML
|
void saveXml(ostream &s) const; ///< Save cached strings to a stream as XML
|
||||||
void restoreXml(const Element *el,const AddrSpaceManager *m); ///< Restore string cache from XML
|
void restoreXml(const Element *el,const AddrSpaceManager *m); ///< Restore string cache from XML
|
||||||
|
@ -72,7 +70,7 @@ public:
|
||||||
StringManagerUnicode(Architecture *g,int4 max); ///< Constructor
|
StringManagerUnicode(Architecture *g,int4 max); ///< Constructor
|
||||||
virtual ~StringManagerUnicode(void);
|
virtual ~StringManagerUnicode(void);
|
||||||
|
|
||||||
virtual const uint1 *getStringData(const Address &addr,Datatype *charType);
|
virtual const vector<uint1> &getStringData(const Address &addr,Datatype *charType);
|
||||||
bool isCharacterConstant(const uint1 *buf,int4 size,int4 charsize) const; ///< Return \b true if buffer looks like unicode
|
bool isCharacterConstant(const uint1 *buf,int4 size,int4 charsize) const; ///< Return \b true if buffer looks like unicode
|
||||||
bool writeUnicode(ostream &s,uint1 *buffer,int4 size,int4 charsize); ///< Write unicode byte array to stream (as UTF8)
|
bool writeUnicode(ostream &s,uint1 *buffer,int4 size,int4 charsize); ///< Write unicode byte array to stream (as UTF8)
|
||||||
};
|
};
|
||||||
|
|
|
@ -1181,6 +1181,35 @@ public class DecompileCallback {
|
||||||
return listing.getFunctionAt(addr);
|
return listing.getFunctionAt(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if there are no "replacement" characters in the string
|
||||||
|
* @param string is the string to test
|
||||||
|
* @return true if no replacements
|
||||||
|
*/
|
||||||
|
private boolean isValidChars(String string) {
|
||||||
|
char replaceChar = '\ufffd';
|
||||||
|
for (int i = 0; i < string.length(); ++i) {
|
||||||
|
char c = string.charAt(i);
|
||||||
|
if (c == replaceChar) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for a string at an address and return a UTF8 encoded byte array.
|
||||||
|
* If there is already data present at the address, use this to determine the
|
||||||
|
* string encoding. Otherwise use the data-type info passed in to determine the encoding.
|
||||||
|
* Check that the bytes at the address represent a valid string encoding that doesn't
|
||||||
|
* exceed the maximum byte limit passed in. Return null if the string is invalid.
|
||||||
|
* Return the string translated into a UTF8 byte array otherwise. A (valid) empty
|
||||||
|
* string is returned as a zero length array.
|
||||||
|
* @param addrString is the XML encoded address and maximum byte limit
|
||||||
|
* @param dtName is the name of a character data-type
|
||||||
|
* @param dtId is the id associated with the character data-type
|
||||||
|
* @return the UTF8 encoded byte array or null
|
||||||
|
*/
|
||||||
public byte[] getStringData(String addrString, String dtName, String dtId) {
|
public byte[] getStringData(String addrString, String dtName, String dtId) {
|
||||||
Address addr;
|
Address addr;
|
||||||
int maxBytes;
|
int maxBytes;
|
||||||
|
@ -1199,9 +1228,21 @@ public class DecompileCallback {
|
||||||
Settings settings = SettingsImpl.NO_SETTINGS;
|
Settings settings = SettingsImpl.NO_SETTINGS;
|
||||||
AbstractStringDataType dataType = null;
|
AbstractStringDataType dataType = null;
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
settings = data;
|
|
||||||
if (data.getDataType() instanceof AbstractStringDataType) {
|
if (data.getDataType() instanceof AbstractStringDataType) {
|
||||||
|
settings = data;
|
||||||
dataType = (AbstractStringDataType) data.getDataType();
|
dataType = (AbstractStringDataType) data.getDataType();
|
||||||
|
int len = data.getLength();
|
||||||
|
if (len > 0) {
|
||||||
|
long diff = addr.subtract(data.getAddress()) *
|
||||||
|
addr.getAddressSpace().getAddressableUnitSize();
|
||||||
|
if (diff < 0 || diff >= len) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
len -= diff;
|
||||||
|
if (len < maxBytes) {
|
||||||
|
maxBytes = len;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (dataType == null) {
|
if (dataType == null) {
|
||||||
|
@ -1228,17 +1269,17 @@ public class DecompileCallback {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MemoryBufferImpl buf = new MemoryBufferImpl(program.getMemory(), addr, 64);
|
MemoryBufferImpl buf = new MemoryBufferImpl(program.getMemory(), addr, 64);
|
||||||
Object value = dataType.getValue(buf, settings, maxBytes);
|
StringDataInstance stringInstance = dataType.getStringDataInstance(buf, settings, maxBytes);
|
||||||
if (!(value instanceof String)) {
|
int len = stringInstance.getStringLength();
|
||||||
|
if (len < 0 || len > maxBytes) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
String stringVal = (String) value;
|
|
||||||
byte[] res = stringVal.getBytes(utf8Charset);
|
String stringVal = stringInstance.getStringValue();
|
||||||
if (res.length > maxBytes) {
|
if (!isValidChars(stringVal)) {
|
||||||
byte[] trim = new byte[maxBytes];
|
return null;
|
||||||
System.arraycopy(res, 0, trim, 0, maxBytes);
|
|
||||||
}
|
}
|
||||||
return res;
|
return stringVal.getBytes(utf8Charset);
|
||||||
}
|
}
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
|
@ -789,19 +789,21 @@ public class DecompileProcess {
|
||||||
String dtId = readQueryString();
|
String dtId = readQueryString();
|
||||||
byte[] res = callback.getStringData(addr, dtName, dtId);
|
byte[] res = callback.getStringData(addr, dtName, dtId);
|
||||||
write(query_response_start);
|
write(query_response_start);
|
||||||
if ((res != null) && (res.length > 0)) {
|
if (res != null) {
|
||||||
int sz = res.length;
|
int sz = res.length + 1; // We add a null terminator character
|
||||||
int sz1 = (sz & 0x3f) + 0x20;
|
int sz1 = (sz & 0x3f) + 0x20;
|
||||||
sz >>>= 6;
|
sz >>>= 6;
|
||||||
int sz2 = (sz & 0x3f) + 0x20;
|
int sz2 = (sz & 0x3f) + 0x20;
|
||||||
write(byte_start);
|
write(byte_start);
|
||||||
write(sz1);
|
write(sz1);
|
||||||
write(sz2);
|
write(sz2);
|
||||||
byte[] dblres = new byte[res.length * 2];
|
byte[] dblres = new byte[res.length * 2 + 2];
|
||||||
for (int i = 0; i < res.length; i++) {
|
for (int i = 0; i < res.length; i++) {
|
||||||
dblres[i * 2] = (byte) (((res[i] >> 4) & 0xf) + 65);
|
dblres[i * 2] = (byte) (((res[i] >> 4) & 0xf) + 65);
|
||||||
dblres[i * 2 + 1] = (byte) ((res[i] & 0xf) + 65);
|
dblres[i * 2 + 1] = (byte) ((res[i] & 0xf) + 65);
|
||||||
}
|
}
|
||||||
|
dblres[res.length * 2] = 65; // Adding null terminator
|
||||||
|
dblres[res.length * 2 + 1] = 65;
|
||||||
write(dblres);
|
write(dblres);
|
||||||
write(byte_end);
|
write(byte_end);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue