@@ -53,6 +53,65 @@ using namespace solidity::evmasm;
53
53
using namespace solidity ::langutil;
54
54
using namespace solidity ::util;
55
55
56
+ namespace
57
+ {
58
+
59
+ // / Produces instruction location info in RAII style. When an assembly instruction is added to the bytecode,
60
+ // / this class can be instantiated in that scope. It will record the current bytecode size (before addition)
61
+ // / and, at destruction time, record the new bytecode size. This information is then added to an external
62
+ // / instruction locations vector.
63
+ // / If the instruction decomposes into multiple individual evm instructions, `emit` can be
64
+ // / called for all but the last one (which will be emitted by the destructor).
65
+ class AddInstructionLocation
66
+ {
67
+ public:
68
+ AddInstructionLocation (
69
+ std::vector<LinkerObject::InstructionLocation>& _instructionLocations,
70
+ bytes const & _bytecode,
71
+ size_t const _assemblyItemIndex
72
+ ):
73
+ m_instructionLocations (_instructionLocations),
74
+ m_bytecode (_bytecode),
75
+ m_assemblyItemIndex (_assemblyItemIndex),
76
+ m_instructionLocationStart (_bytecode.size())
77
+ {}
78
+
79
+ ~AddInstructionLocation ()
80
+ {
81
+ emit ();
82
+ }
83
+
84
+ void emit ()
85
+ {
86
+ // deals with EOF tag instructions that do not have any meaningful source location and also don't contribute
87
+ // to the bytecode
88
+ if (m_skip)
89
+ return ;
90
+
91
+ auto const end = m_bytecode.size ();
92
+ m_instructionLocations.emplace_back (LinkerObject::InstructionLocation{
93
+ .start = m_instructionLocationStart,
94
+ .end = end,
95
+ .assemblyItemIndex = m_assemblyItemIndex
96
+ });
97
+ m_instructionLocationStart = end;
98
+ }
99
+
100
+ void skip ()
101
+ {
102
+ m_skip = true ;
103
+ }
104
+
105
+ private:
106
+ std::vector<LinkerObject::InstructionLocation>& m_instructionLocations;
107
+ bytes const & m_bytecode;
108
+ size_t const m_assemblyItemIndex;
109
+ size_t m_instructionLocationStart;
110
+ bool m_skip = false ;
111
+ };
112
+
113
+ }
114
+
56
115
std::map<std::string, std::shared_ptr<std::string const >> Assembly::s_sharedSourceNames;
57
116
58
117
AssemblyItem const & Assembly::append (AssemblyItem _i)
@@ -1607,9 +1666,17 @@ LinkerObject const& Assembly::assembleEOF() const
1607
1666
for (auto && [codeSectionIndex, codeSection]: m_codeSections | ranges::views::enumerate)
1608
1667
{
1609
1668
auto const sectionStart = ret.bytecode .size ();
1669
+
1670
+ std::vector<LinkerObject::InstructionLocation> instructionLocations;
1671
+ instructionLocations.reserve (codeSection.items .size ());
1672
+
1610
1673
solAssert (!codeSection.items .empty (), " Empty code section." );
1611
- for (AssemblyItem const & item: codeSection.items )
1674
+
1675
+ for (auto const & [assemblyItemIndex, item]: codeSection.items | ranges::views::enumerate)
1612
1676
{
1677
+ // collect instruction locations via side effects
1678
+ AddInstructionLocation addInstructionLocation {instructionLocations, ret.bytecode , assemblyItemIndex};
1679
+
1613
1680
// store position of the invalid jump destination
1614
1681
if (item.type () != Tag && m_tagPositionsInBytecode[0 ] == std::numeric_limits<size_t >::max ())
1615
1682
m_tagPositionsInBytecode[0 ] = ret.bytecode .size ();
@@ -1676,6 +1743,8 @@ LinkerObject const& Assembly::assembleEOF() const
1676
1743
break ;
1677
1744
case Tag:
1678
1745
ret.bytecode += assembleTag (item, ret.bytecode .size (), false );
1746
+ // since no jumpdest is added, these tags do not contribute to the bytecode
1747
+ addInstructionLocation.skip ();
1679
1748
break ;
1680
1749
case AuxDataLoadN:
1681
1750
{
@@ -1725,6 +1794,12 @@ LinkerObject const& Assembly::assembleEOF() const
1725
1794
" Code section too large for EOF."
1726
1795
);
1727
1796
setBigEndianUint16 (ret.bytecode , codeSectionSizePositions[codeSectionIndex], ret.bytecode .size () - sectionStart);
1797
+
1798
+ ret.codeSectionLocations .emplace_back (LinkerObject::CodeSectionLocation{
1799
+ .start = sectionStart,
1800
+ .end = ret.bytecode .size (),
1801
+ .instructionLocations = std::move (instructionLocations)
1802
+ });
1728
1803
}
1729
1804
1730
1805
for (auto const & [refPos, tagId]: tagRef)
0 commit comments