Skip to content

Commit

Permalink
Assembly output for Assembly object.
Browse files Browse the repository at this point in the history
  • Loading branch information
chriseth committed Jan 3, 2017
1 parent 0bd8c20 commit a285ca4
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 51 deletions.
69 changes: 18 additions & 51 deletions libevmasm/Assembly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
82 changes: 82 additions & 0 deletions libevmasm/AssemblyItem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
*/

#include "AssemblyItem.h"
#include <libevmasm/SemanticInformation.h>
#include <fstream>

using namespace std;
Expand Down Expand Up @@ -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)
Expand All @@ -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())
Expand Down
5 changes: 5 additions & 0 deletions libevmasm/AssemblyItem.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ class AssemblyItem
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; }
Expand All @@ -108,6 +111,8 @@ class AssemblyItem
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;
Expand Down

0 comments on commit a285ca4

Please sign in to comment.