@@ -70,9 +70,13 @@ VxcoreParser::parseUrl(const std::string &spec) {
70
70
throw Exception ("URL" , 0 , "invalid file attribute for vxcore URL: \"" + StringUtility ::cEscape (parts [1 ]) + "\"" );
71
71
}
72
72
}
73
- if (settings_ .version != 1 )
73
+ if (settings_ .version != 1 && settings_ . version != 2 )
74
74
throw Exception ("URL" , 0 , "vxcore version " + boost ::lexical_cast < std ::string > (settings_ .version ) + " is not supported" );
75
75
76
+ // Error checking
77
+ if (2 == settings_ .version && settings_ .protOverride )
78
+ throw Exception ("URL" , 0 , "vxcore version 2 does not support memory protection override (\"=\" attribute)" );
79
+
76
80
return parts [2 ];
77
81
}
78
82
@@ -97,18 +101,64 @@ VxcoreParser::parse(const boost::filesystem::path &fileName, const MemoryMap::Pt
97
101
void
98
102
VxcoreParser ::parse (std ::istream & input , const MemoryMap ::Ptr & memory , const BaseSemantics ::RegisterState ::Ptr & registers ,
99
103
const BaseSemantics ::RiscOperators ::Ptr & ops , const std ::string & inputName ) {
100
- for (size_t segmentIdx = 0 ; input ; ++ segmentIdx ) {
101
- size_t headerOffset = input .tellg ();
102
- std ::string header = rose_getline (input );
103
- if (header .empty ())
104
- break ; // EOF
105
-
106
- std ::string name = inputName + " segment #" + boost ::lexical_cast < std ::string > (segmentIdx );
107
- if (!parseMemory (header , input , memory , name , headerOffset ) &&
108
- !parseRegisters (header , input , registers , ops , name , headerOffset )) {
109
- throw Exception (inputName , input .tellg (), "invalid header: \"" + StringUtility ::cEscape (header .substr (0 , 30 )) + "\"" +
110
- (header .size () > 30 ? "..." : "" ));
104
+ Sawyer ::Message ::Stream debug (mlog [DEBUG ]);
105
+ if (1 == settings_ .version ) {
106
+ for (size_t segmentIdx = 0 ; input ; ++ segmentIdx ) {
107
+ size_t headerOffset = input .tellg ();
108
+ std ::string header = rose_getline (input );
109
+ if (header .empty ())
110
+ break ; // EOF
111
+
112
+ std ::string name = inputName + " segment #" + boost ::lexical_cast < std ::string > (segmentIdx );
113
+ if (!parseMemory (header , input , memory , name , headerOffset ) &&
114
+ !parseRegisters (header , input , registers , ops , name , headerOffset )) {
115
+ throw Exception (inputName , input .tellg (), "invalid header: \"" + StringUtility ::cEscape (header .substr (0 , 30 )) + "\"" +
116
+ (header .size () > 30 ? "..." : "" ));
117
+ }
111
118
}
119
+ } else if (2 == settings_ .version ) {
120
+ while (true) {
121
+ // Read the message header
122
+ HeaderVersion2 header ;
123
+ const size_t headerOffset = input .tellg ();
124
+ input .read ((char * )& header , sizeof header );
125
+ const size_t nHeader = input .gcount ();
126
+ header .payloadSize = BitOps ::fromLittleEndian (header .payloadSize );
127
+ header .addr = BitOps ::fromLittleEndian (header .addr );
128
+
129
+ if (0 == nHeader ) {
130
+ break ;
131
+ } else if (nHeader != sizeof header ) {
132
+ throw Exception (inputName , headerOffset ,
133
+ (boost ::format ("short read (expected %1%, got only %2%) at %3%" )
134
+ % sizeof (header ) % nHeader % headerOffset ).str ());
135
+ } else if (2 != header .version ) {
136
+ throw Exception (inputName , headerOffset ,
137
+ (boost ::format ("invalid message version (expected %1%, got %2%) at %3%" )
138
+ % settings_ .version % header .version % headerOffset ).str ());
139
+ } else if (header .unused0 || header .unused1 ) {
140
+ throw Exception (inputName , headerOffset , (boost ::format ("unused fields must be zero at %1%" ) % headerOffset ).str ());
141
+ } else if (header .mapFlags & ~MemoryMap ::READ_WRITE_EXECUTE ) {
142
+ throw Exception (inputName , headerOffset , (boost ::format ("invalid map flags at %1 %") % headerOffset ).str ());
143
+ } else if (header .payloadSize > 0 ) {
144
+ std ::vector < uint8_t > buf (header .payloadSize );
145
+ input .read ((char * )buf .data (), header .payloadSize );
146
+ const size_t nPayload = input .gcount ();
147
+ if (nPayload != header .payloadSize ) {
148
+ throw Exception (inputName , headerOffset ,
149
+ (boost ::format ("short payload read (expected %1%, got only %2%) at %3%)" )
150
+ % header .payloadSize % nPayload % (headerOffset + sizeof header )).str ());
151
+ } else if (memory ) {
152
+ const auto where = AddressInterval ::baseSize (header .addr , header .payloadSize );
153
+ SAWYER_MESG (debug ) <<"vxcore: addresses " <<StringUtility ::addrToString (where ) <<" at " <<headerOffset <<"\n" ;
154
+ memory -> insert (where , MemoryMap ::Segment ::anonymousInstance (header .payloadSize , header .mapFlags , inputName ));
155
+ const size_t nCopied = memory -> at (header .addr ).limit (header .payloadSize ).write (buf .data ()).size ();
156
+ ASSERT_always_require (nCopied == header .payloadSize );
157
+ }
158
+ }
159
+ }
160
+ } else {
161
+ ASSERT_not_implemented ("vxcore version " + boost ::lexical_cast < std ::string > (settings_ .version ));
112
162
}
113
163
}
114
164
@@ -222,19 +272,34 @@ VxcoreParser::unparse(std::ostream &out, const MemoryMap::Ptr &memory, const Add
222
272
const std ::string & outputName ) {
223
273
if (memory && !memoryLimit .isEmpty ()) {
224
274
rose_addr_t va = memoryLimit .least ();
225
- while (const AddressInterval selected = memory -> atOrAfter (va ).singleSegment ().available () & memoryLimit ) {
275
+ const size_t maxPayload = 0xffffffff ;
276
+ while (const AddressInterval selected = memory -> atOrAfter (va ).limit (maxPayload ).singleSegment ().available () & memoryLimit ) {
226
277
MemoryMap ::ConstNodeIterator inode = memory -> at (selected .least ()).nodes ().begin ();
227
278
ASSERT_forbid (inode == memory -> nodes ().end ()); // because of the while loop's condition
228
279
ASSERT_require (inode -> key ().contains (selected ));
229
280
const MemoryMap ::Segment & segment = inode -> value ();
230
281
231
282
// Header
232
- out <<StringUtility ::addrToString (selected .least ()).substr (2 )
233
- <<" " <<StringUtility ::addrToString (selected .size ()).substr (2 )
234
- <<" =" <<(0 != (segment .accessibility () & MemoryMap ::READABLE ) ? "R" : "-" )
235
- <<(0 != (segment .accessibility () & MemoryMap ::WRITABLE ) ? "W" : "-" )
236
- <<(0 != (segment .accessibility () & MemoryMap ::EXECUTABLE ) ? "X" : "-" )
237
- <<"\n" ;
283
+ if (1 == settings_ .version ) {
284
+ out <<StringUtility ::addrToString (selected .least ()).substr (2 )
285
+ <<" " <<StringUtility ::addrToString (selected .size ()).substr (2 )
286
+ <<" =" <<(0 != (segment .accessibility () & MemoryMap ::READABLE ) ? "R" : "-" )
287
+ <<(0 != (segment .accessibility () & MemoryMap ::WRITABLE ) ? "W" : "-" )
288
+ <<(0 != (segment .accessibility () & MemoryMap ::EXECUTABLE ) ? "X" : "-" )
289
+ <<"\n" ;
290
+ } else if (2 == settings_ .version ) {
291
+ HeaderVersion2 header ;
292
+ memset (& header , 0 , sizeof header );
293
+ header .version = settings_ .version ;
294
+ header .mapFlags = segment .accessibility () & MemoryMap ::READ_WRITE_EXECUTE ;
295
+ header .payloadSize = BitOps ::toLittleEndian (boost ::numeric_cast < uint32_t > (selected .size ()));
296
+ header .addr = BitOps ::toLittleEndian (boost ::numeric_cast < uint64_t > (selected .least ()));
297
+ out .write ((const char * )& header , sizeof header );
298
+ if (!out .good ())
299
+ throw Exception (outputName , out .tellp (), "write failed" );
300
+ } else {
301
+ ASSERT_not_implemented ("vxcore version " + boost ::lexical_cast < std ::string > (settings_ .version ));
302
+ }
238
303
239
304
// Data output one buffer-full at a time since the memory map' underlying buffer might not be storing the bytes
240
305
// contiguously, but we need contiguous bytes for std::ostream::write.
@@ -265,16 +330,22 @@ VxcoreParser::unparse(std::ostream &out, const MemoryMap::Ptr &memory, const Add
265
330
}
266
331
267
332
if (registers ) {
268
- ASSERT_not_null (ops );
269
- out <<"registers " <<registers -> registerDictionary ()-> name () <<"\n" ;
270
- RegisterDictionary ::RegisterDescriptors regs = registers -> registerDictionary ()-> getLargestRegisters ();
271
- RegisterNames registerName (registers -> registerDictionary ());
272
- BOOST_FOREACH (RegisterDescriptor reg , regs ) {
273
- BaseSemantics ::SValue ::Ptr val = registers -> peekRegister (reg , ops -> undefined_ (reg .nBits ()), ops .get ());
274
- if (auto number = val -> toUnsigned ())
275
- out <<(boost ::format ("%s 0x%x\n" ) % registerName (reg ) % * number );
333
+ if (1 == settings_ .version ) {
334
+ ASSERT_not_null (ops );
335
+ out <<"registers " <<registers -> registerDictionary ()-> name () <<"\n" ;
336
+ RegisterDictionary ::RegisterDescriptors regs = registers -> registerDictionary ()-> getLargestRegisters ();
337
+ RegisterNames registerName (registers -> registerDictionary ());
338
+ BOOST_FOREACH (RegisterDescriptor reg , regs ) {
339
+ BaseSemantics ::SValue ::Ptr val = registers -> peekRegister (reg , ops -> undefined_ (reg .nBits ()), ops .get ());
340
+ if (auto number = val -> toUnsigned ())
341
+ out <<(boost ::format ("%s 0x%x\n" ) % registerName (reg ) % * number );
342
+ }
343
+ out <<"end\n" ;
344
+ } else if (2 == settings_ .version ) {
345
+ // Registers are not stored for version 2
346
+ } else {
347
+ ASSERT_not_implemented ("vxcore version " + boost ::lexical_cast < std ::string > (settings_ .version ));
276
348
}
277
- out <<"end\n" ;
278
349
}
279
350
}
280
351
0 commit comments