mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +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 "typegrp_ghidra.hh"
|
||||
#include "comment_ghidra.hh"
|
||||
#include "string_ghidra.hh"
|
||||
#include "cpool_ghidra.hh"
|
||||
#include "inject_ghidra.hh"
|
||||
|
||||
|
@ -346,6 +347,12 @@ void ArchitectureGhidra::buildCommentDB(DocumentStorage &store)
|
|||
commentdb = new CommentDatabaseGhidra(this);
|
||||
}
|
||||
|
||||
void ArchitectureGhidra::buildStringManager(DocumentStorage &store)
|
||||
|
||||
{
|
||||
stringManager = new GhidraStringManager(this,2048);
|
||||
}
|
||||
|
||||
void ArchitectureGhidra::buildConstantPool(DocumentStorage &store)
|
||||
|
||||
{
|
||||
|
@ -615,7 +622,7 @@ void ArchitectureGhidra::getBytes(uint1 *buf,int4 size,const Address &inaddr)
|
|||
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);
|
||||
|
@ -633,32 +640,28 @@ uint4 ArchitectureGhidra::getStringData(uint1 *buf,const Address &addr,Datatype
|
|||
|
||||
readToResponse(sin);
|
||||
int4 type = readToAnyBurst(sin);
|
||||
uint4 size = 0;
|
||||
if (type == 12) {
|
||||
int4 c = sin.get();
|
||||
size ^= (c-0x20);
|
||||
uint4 size = (c-0x20);
|
||||
c = sin.get();
|
||||
size ^= ((c-0x20)<<6);
|
||||
buffer.reserve(size);
|
||||
uint1 *dblbuf = new uint1[size * 2];
|
||||
sin.read((char *)dblbuf,size*2);
|
||||
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;
|
||||
type = readToAnyBurst(sin);
|
||||
if (type != 13)
|
||||
throw JavaError("alignment","Expecting byte alignment end");
|
||||
type = readToAnyBurst(sin);
|
||||
}
|
||||
else if ((type&1)==1) {
|
||||
ostringstream errmsg;
|
||||
errmsg << "GHIDRA has no string in the loadimage at " << addr.getShortcut();
|
||||
addr.printRaw(errmsg);
|
||||
throw DataUnavailError(errmsg.str());
|
||||
if ((type&1)==1) {
|
||||
// Leave the buffer empty
|
||||
}
|
||||
else
|
||||
throw JavaError("alignment","Expecting bytes or end of query response");
|
||||
type = readToAnyBurst(sin);
|
||||
if (type != 13)
|
||||
throw JavaError("alignment","Expecting byte alignment end");
|
||||
readResponseEnd(sin);
|
||||
return size;
|
||||
throw JavaError("alignment","Expecting end of query response");
|
||||
}
|
||||
|
||||
/// \brief Retrieve p-code to inject for a specific context
|
||||
|
|
|
@ -74,6 +74,7 @@ class ArchitectureGhidra : public Architecture {
|
|||
virtual PcodeInjectLibrary *buildPcodeInjectLibrary(void);
|
||||
virtual void buildTypegrp(DocumentStorage &store);
|
||||
virtual void buildCommentDB(DocumentStorage &store);
|
||||
virtual void buildStringManager(DocumentStorage &store);
|
||||
virtual void buildConstantPool(DocumentStorage &store);
|
||||
virtual void buildContext(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
|
||||
|
||||
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;
|
||||
|
||||
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 IfcCallOtherFixup(),"fixup","callother");
|
||||
status->registerCom(new IfcVolatile(),"volatile");
|
||||
status->registerCom(new IfcReadonly(),"readonly");
|
||||
status->registerCom(new IfcPreferSplit(),"prefersplit");
|
||||
status->registerCom(new IfcStructureBlocks(),"structure","blocks");
|
||||
status->registerCom(new IfcAnalyzeRange(), "analyze","range");
|
||||
|
@ -2304,6 +2305,22 @@ void IfcVolatile::execute(istream &s)
|
|||
*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)
|
||||
|
||||
{ // Mark a particular storage location as something we would prefer to split
|
||||
|
|
|
@ -531,6 +531,11 @@ public:
|
|||
virtual void execute(istream &s);
|
||||
};
|
||||
|
||||
class IfcReadonly : public IfaceDecompCommand {
|
||||
public:
|
||||
virtual void execute(istream &s);
|
||||
};
|
||||
|
||||
class IfcPreferSplit : public IfaceDecompCommand {
|
||||
public:
|
||||
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
|
||||
|
||||
{
|
||||
const uint1 *buffer;
|
||||
StringManager *manager = glb->stringManager;
|
||||
try {
|
||||
buffer = manager->getStringData(addr, charType);
|
||||
} catch(DataUnavailError &err) {
|
||||
|
||||
// Retrieve UTF8 version of string
|
||||
const vector<uint1> &buffer(manager->getStringData(addr, charType));
|
||||
if (buffer.empty())
|
||||
return false;
|
||||
}
|
||||
if (doEmitWideCharPrefix() && charType->getSize() > 1)
|
||||
s << 'L'; // Print symbol indicating wide character
|
||||
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 */";
|
||||
else
|
||||
s << '"';
|
||||
else {
|
||||
if (buffer.size() > manager->getMaximumBytes())
|
||||
s << "...\" /* TRUNCATED STRING LITERAL */";
|
||||
else
|
||||
s << '"';
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "ghidra_string.hh"
|
||||
#include "string_ghidra.hh"
|
||||
|
||||
GhidraStringManager::GhidraStringManager(ArchitectureGhidra *g,int4 max)
|
||||
: StringManager(max)
|
||||
|
@ -28,14 +28,15 @@ GhidraStringManager::~GhidraStringManager(void)
|
|||
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);
|
||||
if (iter != stringMap.end())
|
||||
return (*iter).second;
|
||||
|
||||
int4 size = glb->getStringData(testBuffer, addr, charType, maximumBytes);
|
||||
return mapBuffer(addr, testBuffer, size);
|
||||
vector<uint1> &buffer(stringMap[addr]);
|
||||
glb->getStringData(buffer, addr, charType, maximumBytes);
|
||||
return buffer;
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ class GhidraStringManager : public StringManager {
|
|||
public:
|
||||
GhidraStringManager(ArchitectureGhidra *g,int4 max); ///< Constructor
|
||||
virtual ~GhidraStringManager(void);
|
||||
virtual const uint1 *getStringData(const Address &addr,Datatype *charType);
|
||||
virtual const vector<uint1> &getStringData(const Address &addr,Datatype *charType);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -16,21 +16,6 @@
|
|||
#include "stringmanage.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
|
||||
StringManager::StringManager(int4 max)
|
||||
|
||||
|
@ -44,16 +29,6 @@ StringManager::~StringManager(void)
|
|||
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
|
||||
/// write the bytes to the 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)
|
||||
|
||||
{
|
||||
const uint1 *buffer = (const uint1 *)0;
|
||||
try {
|
||||
buffer = getStringData(addr,charType);
|
||||
}
|
||||
catch(DataUnavailError &err) {
|
||||
return false;
|
||||
}
|
||||
return (buffer != (const uint1 *)0);
|
||||
const vector<uint1> &buffer(getStringData(addr,charType));
|
||||
return !buffer.empty();
|
||||
}
|
||||
|
||||
/// Write \<stringmanage> tag, with \<string> sub-tags.
|
||||
|
@ -120,15 +89,14 @@ void StringManager::saveXml(ostream &s) const
|
|||
{
|
||||
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) {
|
||||
s << "<string>\n";
|
||||
(*iter1).first.saveXml(s);
|
||||
const uint1 *buf = (*iter1).second;
|
||||
const vector<uint1> &vec( (*iter1).second );
|
||||
s << " <bytes>\n" << setfill('0');
|
||||
for(int4 i=0;;++i) {
|
||||
if (buf[i] == 0) break;
|
||||
s << hex << setw(2) << (int4)buf[i];
|
||||
for(int4 i=0;vec.size();++i) {
|
||||
s << hex << setw(2) << (int4)vec[i];
|
||||
if (i%20 == 19)
|
||||
s << "\n ";
|
||||
}
|
||||
|
@ -148,7 +116,7 @@ void StringManager::restoreXml(const Element *el,const AddrSpaceManager *m)
|
|||
iter = list.begin();
|
||||
Address addr = Address::restoreXml(*iter, m);
|
||||
++iter;
|
||||
vector<uint1> vec;
|
||||
vector<uint1> &vec(stringMap[addr]);
|
||||
istringstream is((*iter)->getContent());
|
||||
int4 val;
|
||||
char c1, c2;
|
||||
|
@ -174,7 +142,6 @@ void StringManager::restoreXml(const Element *el,const AddrSpaceManager *m)
|
|||
c1 = is.get();
|
||||
c2 = is.get();
|
||||
}
|
||||
mapBuffer(addr,vec.data(),vec.size());
|
||||
}
|
||||
|
||||
/// \param buffer is the byte buffer
|
||||
|
@ -300,49 +267,61 @@ StringManagerUnicode::~StringManagerUnicode(void)
|
|||
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);
|
||||
if (iter != stringMap.end())
|
||||
return (*iter).second;
|
||||
|
||||
vector<uint1> &vec(stringMap[addr]); // Allocate (initially empty) byte vector
|
||||
|
||||
int4 curBufferSize = 0;
|
||||
int4 charsize = charType->getSize();
|
||||
bool foundTerminator = false;
|
||||
|
||||
do {
|
||||
int4 amount = 32; // Grab 32 bytes of image at a time
|
||||
uint4 newBufferSize = curBufferSize + amount;
|
||||
if (newBufferSize > maximumBytes) {
|
||||
newBufferSize = maximumBytes;
|
||||
amount = newBufferSize - curBufferSize;
|
||||
if (amount == 0) break;
|
||||
}
|
||||
glb->loader->loadFill(testBuffer+curBufferSize,amount,addr + curBufferSize);
|
||||
foundTerminator = hasCharTerminator(testBuffer+curBufferSize,amount,charsize);
|
||||
curBufferSize = newBufferSize;
|
||||
} while (!foundTerminator);
|
||||
try {
|
||||
do {
|
||||
int4 amount = 32; // Grab 32 bytes of image at a time
|
||||
uint4 newBufferSize = curBufferSize + amount;
|
||||
if (newBufferSize > maximumBytes) {
|
||||
newBufferSize = maximumBytes;
|
||||
amount = newBufferSize - curBufferSize;
|
||||
if (amount == 0)
|
||||
break;
|
||||
}
|
||||
glb->loader->loadFill(testBuffer + curBufferSize, amount,
|
||||
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 (!isCharacterConstant(testBuffer,curBufferSize,charsize))
|
||||
return (const uint1 *)0;
|
||||
resBuffer = mapBuffer(addr,testBuffer,curBufferSize);
|
||||
return vec; // Return the empty buffer
|
||||
vec.reserve(curBufferSize);
|
||||
vec.assign(testBuffer,testBuffer+curBufferSize);
|
||||
}
|
||||
else {
|
||||
// We need to translate to UTF8
|
||||
ostringstream s;
|
||||
if (!writeUnicode(s, testBuffer, curBufferSize, charsize))
|
||||
return (const uint1 *)0;
|
||||
return vec; // Return the empty buffer
|
||||
string resString = s.str();
|
||||
int4 newSize = resString.size();
|
||||
if (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
|
||||
|
|
|
@ -30,27 +30,25 @@ class Architecture;
|
|||
/// Stores the decoded string until its needed for presentation.
|
||||
class StringManager {
|
||||
protected:
|
||||
map<Address,const uint1 *> stringMap; ///< Map from address to string (in UTF8 format)
|
||||
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
|
||||
map<Address,vector<uint1> > stringMap; ///< Map from address to string (in UTF8 format)
|
||||
int4 maximumBytes; ///< Maximum bytes (in UTF8 encoding) allowed
|
||||
public:
|
||||
StringManager(int4 max); ///< Constructor
|
||||
virtual ~StringManager(void); ///< Destructor
|
||||
|
||||
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
|
||||
|
||||
/// \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.
|
||||
/// \param addr is the given address
|
||||
/// \param charType is a character data-type indicating the encoding
|
||||
/// \return the byte array of UTF8 data (or null)
|
||||
virtual const uint1 *getStringData(const Address &addr,Datatype *charType)=0;
|
||||
/// \return the byte array of UTF8 data
|
||||
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 restoreXml(const Element *el,const AddrSpaceManager *m); ///< Restore string cache from XML
|
||||
|
@ -72,7 +70,7 @@ public:
|
|||
StringManagerUnicode(Architecture *g,int4 max); ///< Constructor
|
||||
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 writeUnicode(ostream &s,uint1 *buffer,int4 size,int4 charsize); ///< Write unicode byte array to stream (as UTF8)
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue