mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Assembly output for Assembly object.
This commit is contained in:
parent
0bd8c204f0
commit
a285ca44f2
@ -117,69 +117,36 @@ string Assembly::locationFromSources(StringMap const& _sourceCodes, SourceLocati
|
||||
|
||||
ostream& Assembly::streamAsm(ostream& _out, string const& _prefix, StringMap const& _sourceCodes) const
|
||||
{
|
||||
_out << _prefix << ".code:" << endl;
|
||||
for (AssemblyItem const& i: m_items)
|
||||
for (size_t i = 0; i < m_items.size(); ++i)
|
||||
{
|
||||
_out << _prefix;
|
||||
switch (i.type())
|
||||
AssemblyItem const& item = m_items[i];
|
||||
if (!item.location().isEmpty() && (i == 0 || m_items[i - 1].location() != item.location()))
|
||||
{
|
||||
case Operation:
|
||||
_out << " " << instructionInfo(i.instruction()).name << "\t" << i.getJumpTypeAsString();
|
||||
break;
|
||||
case Push:
|
||||
_out << " PUSH" << dec << max<unsigned>(1, dev::bytesRequired(i.data())) << " 0x" << hex << i.data();
|
||||
break;
|
||||
case PushString:
|
||||
_out << " PUSH \"" << m_strings.at((h256)i.data()) << "\"";
|
||||
break;
|
||||
case PushTag:
|
||||
if (i.data() == 0)
|
||||
_out << " PUSH [ErrorTag]";
|
||||
else
|
||||
{
|
||||
size_t subId = i.splitForeignPushTag().first;
|
||||
if (subId == size_t(-1))
|
||||
_out << " PUSH [tag" << dec << i.splitForeignPushTag().second << "]";
|
||||
else
|
||||
_out << " PUSH [tag" << dec << subId << ":" << i.splitForeignPushTag().second << "]";
|
||||
}
|
||||
break;
|
||||
case PushSub:
|
||||
_out << " PUSH [$" << size_t(i.data()) << "]";
|
||||
break;
|
||||
case PushSubSize:
|
||||
_out << " PUSH #[$" << size_t(i.data()) << "]";
|
||||
break;
|
||||
case PushProgramSize:
|
||||
_out << " PUSHSIZE";
|
||||
break;
|
||||
case PushLibraryAddress:
|
||||
_out << " PUSHLIB \"" << m_libraries.at(h256(i.data())) << "\"";
|
||||
break;
|
||||
case Tag:
|
||||
_out << "tag" << dec << i.data() << ": " << endl << _prefix << " JUMPDEST";
|
||||
break;
|
||||
case PushData:
|
||||
_out << " PUSH [" << hex << (unsigned)i.data() << "]";
|
||||
break;
|
||||
default:
|
||||
BOOST_THROW_EXCEPTION(InvalidOpcode());
|
||||
_out << _prefix << " /*";
|
||||
if (item.location().sourceName)
|
||||
_out << " \"" + *item.location().sourceName + "\"";
|
||||
if (!item.location().isEmpty())
|
||||
_out << ":" << to_string(item.location().start) + ":" + to_string(item.location().end);
|
||||
_out << " */" << endl;
|
||||
}
|
||||
_out << "\t\t" << locationFromSources(_sourceCodes, i.location()) << endl;
|
||||
_out << _prefix << (item.type() == Tag ? "" : " ") << item.toAssemblyText() << endl;
|
||||
}
|
||||
|
||||
if (!m_data.empty() || !m_subs.empty())
|
||||
{
|
||||
_out << _prefix << ".data:" << endl;
|
||||
_out << _prefix << "stop" << endl;
|
||||
Json::Value data;
|
||||
for (auto const& i: m_data)
|
||||
if (u256(i.first) >= m_subs.size())
|
||||
_out << _prefix << " " << hex << (unsigned)(u256)i.first << ": " << dev::toHex(i.second) << endl;
|
||||
assertThrow(u256(i.first) < m_subs.size(), AssemblyException, "Data not yet implemented.");
|
||||
|
||||
for (size_t i = 0; i < m_subs.size(); ++i)
|
||||
{
|
||||
_out << _prefix << " " << hex << i << ": " << endl;
|
||||
m_subs[i]->stream(_out, _prefix + " ", _sourceCodes);
|
||||
_out << endl << _prefix << "sub_" << i << ": assembly {\n";
|
||||
m_subs[i]->streamAsm(_out, _prefix + " ", _sourceCodes);
|
||||
_out << _prefix << "}" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
return _out;
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
*/
|
||||
|
||||
#include "AssemblyItem.h"
|
||||
#include <libevmasm/SemanticInformation.h>
|
||||
#include <fstream>
|
||||
|
||||
using namespace std;
|
||||
@ -97,6 +98,28 @@ int AssemblyItem::deposit() const
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool AssemblyItem::canBeFunctional() const
|
||||
{
|
||||
switch (m_type)
|
||||
{
|
||||
case Operation:
|
||||
return !SemanticInformation::isDupInstruction(*this) && !SemanticInformation::isSwapInstruction(*this);
|
||||
case Push:
|
||||
case PushString:
|
||||
case PushTag:
|
||||
case PushData:
|
||||
case PushSub:
|
||||
case PushSubSize:
|
||||
case PushProgramSize:
|
||||
case PushLibraryAddress:
|
||||
return true;
|
||||
case Tag:
|
||||
return false;
|
||||
default:;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
string AssemblyItem::getJumpTypeAsString() const
|
||||
{
|
||||
switch (m_jumpType)
|
||||
@ -111,6 +134,65 @@ string AssemblyItem::getJumpTypeAsString() const
|
||||
}
|
||||
}
|
||||
|
||||
string AssemblyItem::toAssemblyText() const
|
||||
{
|
||||
string text;
|
||||
switch (type())
|
||||
{
|
||||
case Operation:
|
||||
{
|
||||
assertThrow(isValidInstruction(instruction()), AssemblyException, "Invalid instruction.");
|
||||
string name = instructionInfo(instruction()).name;
|
||||
transform(name.begin(), name.end(), name.begin(), [](unsigned char _c) { return tolower(_c); });
|
||||
text = name;
|
||||
break;
|
||||
}
|
||||
case Push:
|
||||
text = toHex(toCompactBigEndian(data(), 1), 1, HexPrefix::Add);
|
||||
break;
|
||||
case PushString:
|
||||
assertThrow(false, AssemblyException, "Push string assembly output not implemented.");
|
||||
break;
|
||||
case PushTag:
|
||||
assertThrow(data() < 0x10000, AssemblyException, "Sub-assembly tags not yet implemented.");
|
||||
text = string("tag_") + to_string(size_t(data()));
|
||||
break;
|
||||
case Tag:
|
||||
assertThrow(data() < 0x10000, AssemblyException, "Sub-assembly tags not yet implemented.");
|
||||
text = string("tag_") + to_string(size_t(data())) + ":";
|
||||
break;
|
||||
case PushData:
|
||||
assertThrow(false, AssemblyException, "Push data not implemented.");
|
||||
break;
|
||||
case PushSub:
|
||||
text = string("dataOffset(sub_") + to_string(size_t(data())) + ")";
|
||||
break;
|
||||
case PushSubSize:
|
||||
text = string("dataSize(sub_") + to_string(size_t(data())) + ")";
|
||||
break;
|
||||
case PushProgramSize:
|
||||
text = string("programSize");
|
||||
break;
|
||||
case PushLibraryAddress:
|
||||
text = string("linkerSymbol(\"") + toHex(data()) + string("\")");
|
||||
break;
|
||||
case UndefinedItem:
|
||||
assertThrow(false, AssemblyException, "Invalid assembly item.");
|
||||
break;
|
||||
default:
|
||||
BOOST_THROW_EXCEPTION(InvalidOpcode());
|
||||
}
|
||||
if (m_jumpType == JumpType::IntoFunction || m_jumpType == JumpType::OutOfFunction)
|
||||
{
|
||||
text += "\t//";
|
||||
if (m_jumpType == JumpType::IntoFunction)
|
||||
text += " in";
|
||||
else
|
||||
text += " out";
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
ostream& dev::eth::operator<<(ostream& _out, AssemblyItem const& _item)
|
||||
{
|
||||
switch (_item.type())
|
||||
|
@ -97,6 +97,9 @@ public:
|
||||
unsigned bytesRequired(unsigned _addressLength) const;
|
||||
int deposit() const;
|
||||
|
||||
/// @returns true if the assembly item can be used in a functional context.
|
||||
bool canBeFunctional() const;
|
||||
|
||||
bool match(AssemblyItem const& _i) const { return _i.m_type == UndefinedItem || (m_type == _i.m_type && (m_type != Operation || m_data == _i.m_data)); }
|
||||
void setLocation(SourceLocation const& _location) { m_location = _location; }
|
||||
SourceLocation const& location() const { return m_location; }
|
||||
@ -108,6 +111,8 @@ public:
|
||||
void setPushedValue(u256 const& _value) const { m_pushedValue = std::make_shared<u256>(_value); }
|
||||
u256 const* pushedValue() const { return m_pushedValue.get(); }
|
||||
|
||||
std::string toAssemblyText() const;
|
||||
|
||||
private:
|
||||
AssemblyItemType m_type;
|
||||
u256 m_data;
|
||||
|
Loading…
Reference in New Issue
Block a user