2 * Copyright (C) 2009, Parrot Foundation.
7 // A multiplatform checker for pbc files
18 // Get most used symbols from std namespace
27 using std::runtime_error
;
29 //**********************************************************************
31 // Type used to read parrot opcodes
32 // You can use unsigned long here if your compiler does not support
33 // long long, but in that case the results might not be accurate.
35 typedef unsigned long long opcode
;
37 // Constants used in pbc and his descriptions
39 const char unknown
[] = "Unknown";
45 const char * desc_byte_order(unsigned char c
)
48 case ByteOrderLE
: return "Little endian";
49 case ByteOrderBE
: return "Big endian";
50 default: return unknown
;
55 FpEncodingIEEE_754_8
= 0,
56 FpEncodingIEEE_i386_12
= 1,
57 FpEncodingIEEE_754_16
= 2;
59 const char * desc_fp_encoding(unsigned char c
)
62 case FpEncodingIEEE_754_8
: return "IEEE 754 8 byte double";
63 case FpEncodingIEEE_i386_12
: return "i386 little endian 12 byte long double";
64 case FpEncodingIEEE_754_16
: return "IEEE 754 16 byte long double";
65 default: return unknown
;
69 const char * desc_uuid_type(unsigned char c
)
72 case 0: return "none";
74 default: return unknown
;
79 SegmentTypeDirectory
= 0x00,
80 SegmentTypeDefault
= 0x01,
81 SegmentTypeFixup
= 0x02,
82 SegmentTypeConstantTable
= 0x03,
83 SegmentTypeBytecode
= 0x04,
84 SegmentTypePIRDebug
= 0x05,
85 SegmentTypeAnnotations
= 0x06,
86 SegmentTypePICData
= 0x07,
87 SegmentTypeDependencies
= 0x08;
89 const char * desc_segment_type(opcode t
)
92 case SegmentTypeDirectory
: return "Directory";
93 case SegmentTypeDefault
: return "Default";
94 case SegmentTypeFixup
: return "Fixup";
95 case SegmentTypeConstantTable
: return "Constant table";
96 case SegmentTypeBytecode
: return "Bytecode";
97 case SegmentTypePIRDebug
: return "PIR Debug";
98 case SegmentTypeAnnotations
: return "Annotations";
99 case SegmentTypePICData
: return "PIC Data";
100 case SegmentTypeDependencies
: return "Dependencies";
101 default: return unknown
;
106 ConstantTypeNone
= 0x00,
107 ConstantTypeNumber
= 0x6E,
108 ConstantTypeString
= 0x73,
109 ConstantTypePMC
= 0x70,
110 ConstantTypeKey
= 0x6B;
112 const char * desc_constant_type(opcode t
)
115 case ConstantTypeNone
: return "None";
116 case ConstantTypeNumber
: return "Number";
117 case ConstantTypeString
: return "String";
118 case ConstantTypePMC
: return "PMC";
119 case ConstantTypeKey
: return "Key";
120 default: return unknown
;
125 KeyIntegerRegister
= 0x00,
126 KeyStringRegister
= 0x01,
127 KeyPMCRegister
= 0x02,
128 KeyNumberRegister
= 0x03,
129 KeyIntegerConstant
= 0x10,
130 KeyStringConstant
= 0x11,
131 KeyPMCConstant
= 0x12,
132 KeyNumberConstant
= 0x13;
134 const char * desc_key_type(opcode t
)
137 case KeyIntegerRegister
: return "Integer register";
138 case KeyStringRegister
: return "String register";
139 case KeyPMCRegister
: return "PMC register";
140 case KeyNumberRegister
: return "Number register";
141 case KeyIntegerConstant
: return "Integer constant";
142 case KeyStringConstant
: return "String constant";
143 case KeyPMCConstant
: return "PMC constant";
144 case KeyNumberConstant
: return "Number constant";
145 default: return unknown
;
150 AnnotationTypeInteger
= 0x00,
151 AnnotationTypeString
= 0x01,
152 AnnotationTypeNumber
= 0x02,
153 AnnotationTypePMC
= 0x03;
155 const char * desc_annotation_type(opcode t
)
158 case AnnotationTypeInteger
: return "Integer";
159 case AnnotationTypeString
: return "String";
160 case AnnotationTypeNumber
: return "Number";
161 case AnnotationTypePMC
: return "PMC";
162 default: return unknown
;
166 //**********************************************************************
168 class ReadError
: public runtime_error
171 ReadError(const string
&msg
);
174 ReadError::ReadError(const string
&msg
) :
175 runtime_error("Error reading " + msg
)
179 //**********************************************************************
181 void signature(ifstream
&pbcfile
)
183 static const char pbc_signature
[] = {
184 0xFE, 0x50, 0x42, 0x43, 0x0D, 0x0A, 0x1A, 0x0A
186 char signature
[sizeof (pbc_signature
)];
187 pbcfile
.read(signature
, sizeof (signature
));
188 if (pbcfile
.gcount() != sizeof (signature
))
189 throw ReadError("pbc signature");
190 if (! std::equal(pbc_signature
, pbc_signature
+ sizeof(pbc_signature
),
192 throw runtime_error("Invalid pbc signature");
195 //**********************************************************************
197 // Emit a open tag in the constructor
198 // and his closing in the destructor.
203 TagEmit(const string
& name_n
, std::ostream
&os_n
);
210 TagEmit::TagEmit(const string
& name_n
, std::ostream
&os_n
) :
211 name(name_n
), os(os_n
)
213 os
<< '<' << name
<< ">\n";
218 os
<< "</" << name
<< ">\n";
221 //**********************************************************************
226 DirEntry(string name_n
, opcode type_n
,
227 opcode offset_n
, opcode length_n
);
228 string
getName() const;
229 opcode
getType() const;
230 opcode
getOffset() const;
231 opcode
getLength() const;
239 DirEntry::DirEntry(string name_n
, opcode type_n
,
240 opcode offset_n
, opcode length_n
) :
248 string
DirEntry::getName() const
253 opcode
DirEntry::getType() const
258 opcode
DirEntry::getOffset() const
263 opcode
DirEntry::getLength() const
268 bool operator < (const DirEntry
& de1
, const DirEntry
& de2
)
270 return de1
.getOffset() < de2
.getOffset();
273 //**********************************************************************
275 // Check that segments does not overlap
277 void check_overlap(const std::vector
<DirEntry
> & directory
)
279 unsigned int entries
= directory
.size();
280 for (unsigned int i
= 0; i
< entries
; ++i
)
282 opcode offset
= directory
[i
].getOffset();
283 opcode length
= directory
[i
].getLength();
284 opcode after
= offset
+ length
;
285 for (unsigned int j
= i
+ 1; j
< entries
; ++j
) {
286 opcode offset2
= directory
[j
].getOffset();
287 if (offset2
>= offset
&& offset2
< after
)
288 throw runtime_error("overlap");
289 opcode after2
= offset2
+ directory
[j
].getLength();
290 if (offset
>= offset2
&& offset
< after2
)
291 throw runtime_error("overlap");
296 //**********************************************************************
302 void read(const char *filename
);
303 void read_header(ifstream
&pbcfile
);
304 void check_directory_format(ifstream
&pbcfile
);
305 void read_directory(ifstream
&pbcfile
);
306 void dump_segment(const DirEntry
& entry
, ifstream
&pbcfile
);
307 void dump_segment_default(ifstream
&pbcfile
);
308 void dump_segment_fixup(ifstream
&pbcfile
);
309 void dump_segment_constant(ifstream
&pbcfile
);
310 void dump_segment_bytecode(ifstream
&pbcfile
);
311 void dump_segment_pir_debug(ifstream
&pbcfile
);
312 void dump_segment_annotations(ifstream
&pbcfile
);
313 void dump_segment_pic_data(ifstream
&pbcfile
);
314 void dump_segment_dependencies(ifstream
&pbcfile
);
315 void dump_constant_string(ifstream
&pbcfile
);
316 void dump_constant_number(ifstream
&pbcfile
);
317 void dump_constant_key(ifstream
&pbcfile
);
318 void dump_bytes_hex(ifstream
&pbcfile
, opcode length
);
319 string
read_cstring(ifstream
&pbcfile
);
320 opcode
read_opcode(ifstream
&pbcfile
);
322 unsigned int opcode_size
;
323 unsigned int pbc_version
;
325 unsigned char byte_order
;
326 unsigned char fp_encoding
;
328 std::vector
<DirEntry
> directory
;
336 void PbcFile::read(const char *filename
)
338 ifstream
pbcfile(filename
);
339 if (! pbcfile
.is_open())
340 throw runtime_error("Can't open file");
342 TagEmit
filetag("PbcFile", cout
);
344 read_header(pbcfile
);
346 check_directory_format(pbcfile
);
347 read_directory(pbcfile
);
348 check_overlap(directory
);
350 std::sort(directory
.begin(), directory
.end());
352 TagEmit
tag("Segments", cout
);
353 for (size_t i
= 0; i
< directory
.size(); ++i
)
354 dump_segment(directory
[i
], pbcfile
);
357 void PbcFile::read_header(ifstream
&pbcfile
)
359 TagEmit
tag("Header", cout
);
362 unsigned char opcode_size
= pbcfile
.get();
363 unsigned char byte_order
= pbcfile
.get();
364 unsigned char fp_encoding
= pbcfile
.get();
365 unsigned char major
= pbcfile
.get();
366 unsigned char minor
= pbcfile
.get();
367 unsigned char patch
= pbcfile
.get();
368 unsigned char pbc_major
= pbcfile
.get();
369 unsigned char pbc_minor
= pbcfile
.get();
372 throw ReadError("pbc header data");
375 "Opcode size : " << (int) opcode_size
<< '\n' <<
376 "Byte order : " << desc_byte_order(byte_order
) <<
377 " (" << (int) byte_order
<< ")\n" <<
378 "Floating point encoding: " << desc_fp_encoding(fp_encoding
) <<
379 " (" << (int) fp_encoding
<< ")\n" <<
380 "Parrot version : " <<
381 (int) major
<< '.' << (int) minor
<< '.' << (int) patch
<< '\n' <<
383 (int) pbc_major
<< '.' << (int) pbc_minor
<< '\n'
386 if (opcode_size
> sizeof(opcode
))
387 cerr
<< "*** Warning: opcode size too big for this program ***\n";
389 this->opcode_size
= opcode_size
;
390 this->pbc_version
= ((unsigned int) pbc_major
) * 8 + pbc_minor
;
391 this->byte_order
= byte_order
;
392 this->fp_encoding
= fp_encoding
;
393 if (byte_order
!= ByteOrderLE
&& byte_order
!= ByteOrderBE
)
394 throw runtime_error("Invalid byte order");
396 unsigned char uuid_type
= pbcfile
.get();
398 "UUID type : " << desc_uuid_type(uuid_type
) <<
399 " (" << (int) uuid_type
<< ")\n"
401 unsigned char uuid_length
= pbcfile
.get();
403 "UUID length : " << (int) uuid_length
<< '\n'
405 unsigned int curpos
= 18 + uuid_length
;
406 unsigned int endheader
= ((curpos
+ 15) / 16) * 16;
407 pbcfile
.ignore(endheader
- 18);
410 void PbcFile::check_directory_format(ifstream
&pbcfile
)
412 TagEmit
tag("DirectoryFormat", cout
);
414 opcode dir_format
= read_opcode(pbcfile
);
415 cout
<< "Directory format: " << dir_format
<< '\n';
417 throw runtime_error("Unknown directory format");
419 opcode unused
= read_opcode(pbcfile
);
420 unused
= read_opcode(pbcfile
);
421 unused
= read_opcode(pbcfile
);
423 for (opcode n
= opcode_size
* 4; n
% 16; ++n
)
427 void PbcFile::read_directory(ifstream
&pbcfile
)
429 TagEmit
tag("Directory", cout
);
431 opcode size
= read_opcode(pbcfile
);
432 cout
<< "Directory segment size: " << size
<< '\n';
434 pbcfile
.ignore(16 - opcode_size
);
435 if (pbc_version
<= 0x0325 && opcode_size
== 8)
438 opcode entries
= read_opcode(pbcfile
);
439 cout
<< "Directory entries: " << entries
<< '\n';
441 for (unsigned int n
= 0; n
< entries
; ++n
)
443 opcode type
= read_opcode(pbcfile
);
445 n
<< ": Type: '" << desc_segment_type(type
) <<
448 string name
= read_cstring(pbcfile
);
450 opcode offset
= read_opcode(pbcfile
);
451 opcode length
= read_opcode(pbcfile
);
453 "'\n Offset: " << offset
<< " Length: " << length
<< '\n';
454 DirEntry
entry(name
, type
, offset
, length
);
455 directory
.push_back(entry
);
459 void PbcFile::dump_segment(const DirEntry
&entry
, ifstream
&pbcfile
)
461 cout
<< "Segment '" << entry
.getName() << "'\n";
462 opcode
const type
= entry
.getType();
463 cout
<< "Type: " << desc_segment_type(type
) <<
464 " (0x" << hex
<< type
<< dec
<< ")\n";
466 // Set file read position to segment's start
467 pbcfile
.seekg(entry
.getOffset() * opcode_size
);
471 case SegmentTypeDirectory
:
472 cout
<< "*** Unexpected directory segment ***\n";
474 case SegmentTypeDefault
:
475 dump_segment_default(pbcfile
);
477 case SegmentTypeFixup
:
478 dump_segment_fixup(pbcfile
);
480 case SegmentTypeConstantTable
:
481 dump_segment_constant(pbcfile
);
483 case SegmentTypeBytecode
:
484 dump_segment_bytecode(pbcfile
);
486 case SegmentTypePIRDebug
:
487 dump_segment_pir_debug(pbcfile
);
489 case SegmentTypeAnnotations
:
490 dump_segment_annotations(pbcfile
);
492 case SegmentTypePICData
:
493 dump_segment_pic_data(pbcfile
);
495 case SegmentTypeDependencies
:
496 dump_segment_dependencies(pbcfile
);
499 cout
<< "*** Unknown segment type ***\n";
504 void PbcFile::dump_segment_default(ifstream
&/*pbcfile*/)
506 TagEmit
tag("SegmentDefault", cout
);
507 cout
<< "*** UNIMPLEMENTED ***\n";
510 void PbcFile::dump_segment_fixup(ifstream
&pbcfile
)
512 TagEmit
tag("SegmentFixup", cout
);
514 opcode segsize
= read_opcode(pbcfile
);
515 cout
<< "Segment size: " << segsize
;
517 opcode itype
= read_opcode(pbcfile
);
518 cout
<< " itype: " << itype
;
519 opcode id
= read_opcode(pbcfile
);
520 cout
<< " id: " << id
;
521 opcode size
= read_opcode(pbcfile
);
522 cout
<< " size: " << size
;
524 opcode tablelength
= read_opcode(pbcfile
);
525 cout
<< " Number of fixups: " << tablelength
<< '\n';
527 for (opcode n
= 0; n
< tablelength
; ++n
) {
528 cout
<< "Fixup " << n
;
529 opcode type
= read_opcode(pbcfile
);
531 " (0x" << hex
<< type
<< dec
<< ')';
535 opcode label
= read_opcode(pbcfile
);
536 cout
<< " Label: " << label
;
537 opcode sub
= read_opcode(pbcfile
);
538 cout
<< " Sub: " << sub
;
543 string label
= read_cstring(pbcfile
);
544 cout
<< " Label: '" << label
<< '\'';
545 opcode sub
= read_opcode(pbcfile
);
546 cout
<< " Sub: " << sub
;
550 throw runtime_error("Invalid fixup");
556 void PbcFile::dump_segment_constant(ifstream
&pbcfile
)
558 TagEmit
tag("SegmentConstantTable", cout
);
560 opcode segsize
= read_opcode(pbcfile
);
561 cout
<< "Segment size: " << segsize
;
563 opcode itype
= read_opcode(pbcfile
);
564 cout
<< " itype: " << itype
;
565 opcode id
= read_opcode(pbcfile
);
566 cout
<< " id: " << id
;
567 opcode size
= read_opcode(pbcfile
);
568 cout
<< " size: " << size
;
570 opcode tablelength
= read_opcode(pbcfile
);
571 cout
<< " Number of constants: " << tablelength
<< '\n';
573 for (opcode n
= 0; n
< tablelength
; ++n
) {
574 cout
<< "Constant " << n
;
575 opcode type
= read_opcode(pbcfile
);
576 cout
<< " Type: " << desc_constant_type(type
) <<
577 " (0x" << hex
<< type
<< dec
<< ") ";
579 case ConstantTypeString
:
580 case ConstantTypePMC
:
581 dump_constant_string(pbcfile
);
583 case ConstantTypeNumber
:
584 dump_constant_number(pbcfile
);
586 case ConstantTypeKey
:
587 dump_constant_key(pbcfile
);
590 throw runtime_error("Unknown constant type");
595 void PbcFile::dump_segment_bytecode(ifstream
&pbcfile
)
597 TagEmit
tag("SegmentBytecode", cout
);
599 opcode segsize
= read_opcode(pbcfile
);
600 cout
<< "Segment size: " << segsize
;
602 opcode itype
= read_opcode(pbcfile
);
603 cout
<< " itype: " << itype
;
604 opcode id
= read_opcode(pbcfile
);
605 cout
<< " id: " << id
;
606 opcode size
= read_opcode(pbcfile
);
607 cout
<< " size: " << size
;
610 for (opcode n
= 0; n
< size
; ++n
) {
611 opcode code
= read_opcode(pbcfile
);
613 cout
<< '\n' << setfill('0') << setw (7) << n
<< ':';
616 cout
<< setfill('0') << setw(opcode_size
* 2) << code
;
621 void PbcFile::dump_segment_pir_debug(ifstream
&pbcfile
)
623 TagEmit
tag("SegmentPIRDebug", cout
);
625 opcode segsize
= read_opcode(pbcfile
);
626 cout
<< "Segment size: " << segsize
;
628 opcode itype
= read_opcode(pbcfile
);
629 cout
<< " itype: " << itype
;
630 opcode id
= read_opcode(pbcfile
);
631 cout
<< " id: " << id
;
632 opcode size
= read_opcode(pbcfile
);
633 cout
<< " size: " << size
;
636 opcode tablelength
= size
;
637 for (opcode n
= 0; n
< tablelength
; ++n
) {
638 opcode linenum
= read_opcode(pbcfile
);
639 cout
<< " Line: " << linenum
;
643 opcode mappings
= read_opcode(pbcfile
);
644 cout
<< "Mappings: " << mappings
<< '\n';
645 for (opcode n
= 0; n
< mappings
; ++n
) {
647 opcode offset
= read_opcode(pbcfile
);
648 cout
<< " Offset: " << offset
;
649 opcode filename
= read_opcode(pbcfile
);
650 cout
<< " File: " << filename
;
655 void PbcFile::dump_segment_annotations(ifstream
&pbcfile
)
657 TagEmit
tag("SegmentAnnotations", cout
);
659 opcode segsize
= read_opcode(pbcfile
);
660 cout
<< "Segment size: " << segsize
;
662 opcode itype
= read_opcode(pbcfile
);
663 cout
<< " itype: " << itype
;
664 opcode id
= read_opcode(pbcfile
);
665 cout
<< " id: " << id
;
666 opcode size
= read_opcode(pbcfile
);
667 cout
<< " size: " << size
;
670 opcode tablelength
= read_opcode(pbcfile
);
671 cout
<< "Number of annotations: " << tablelength
<< '\n';
673 for (opcode i
= 0; i
< tablelength
; ++i
) {
675 opcode name
= read_opcode(pbcfile
);
676 cout
<< " Name: " << name
;
677 opcode type
= read_opcode(pbcfile
);
678 cout
<< " Type: " << desc_annotation_type(type
) << '\n';
681 opcode grouplength
= read_opcode(pbcfile
);
682 cout
<< "Number of annotation groups: " << grouplength
<< '\n';
683 for (opcode i
= 0; i
< grouplength
; ++i
) {
685 opcode bcpos
= read_opcode(pbcfile
);
686 cout
<< " Bytecode offset: " << bcpos
;
687 opcode value
= read_opcode(pbcfile
);
688 cout
<< " Value: " << value
<< '\n';
691 opcode mappings
= read_opcode(pbcfile
);
692 cout
<< "Number of mappings: " << mappings
<< '\n';
693 for (opcode i
= 0; i
< mappings
; ++i
) {
695 opcode bcpos
= read_opcode(pbcfile
);
696 cout
<< " Bytecode offset: " << bcpos
;
697 opcode annotation
= read_opcode(pbcfile
);
698 cout
<< " Annotation key: " << annotation
;
699 opcode value
= read_opcode(pbcfile
);
700 cout
<< " Value: " << value
<< '\n';
704 void PbcFile::dump_segment_pic_data(ifstream
&/*pbcfile*/)
706 TagEmit
tag("SegmentPICData", cout
);
707 cout
<< "*** UNIMPLEMENTED ***\n";
710 void PbcFile::dump_segment_dependencies(ifstream
&/*pbcfile*/)
712 TagEmit
tag("SegmentDependencies", cout
);
713 cout
<< "*** UNIMPLEMENTED ***\n";
716 void PbcFile::dump_constant_string(ifstream
&pbcfile
)
718 opcode flags
= read_opcode(pbcfile
);
719 cout
<< "Flags: 0x" << hex
<< flags
<< dec
;
720 opcode charset
= read_opcode(pbcfile
);
721 cout
<< " Charset: " << charset
;
723 //opcode encoding = read_opcode(pbcfile);
724 //cout << " Encoding: "<< encoding;
726 opcode length
= read_opcode(pbcfile
);
727 cout
<< " Length: "<< length
;
729 for (opcode i
= 0; i
< length
; ++i
) {
730 unsigned char c
= pbcfile
.get();
731 if (c
>= 32 && c
< 128)
734 cout
<< "\\x" << hex
<< setw(2) << setfill('0') <<
735 (unsigned int) c
<< dec
;
738 for (unsigned int i
= length
; i
% opcode_size
; ++i
) {
743 void PbcFile::dump_constant_number(ifstream
&pbcfile
)
745 cout
<< "Number constant: ";
746 switch(fp_encoding
) {
747 case FpEncodingIEEE_754_8
:
748 dump_bytes_hex(pbcfile
, 8);
750 case FpEncodingIEEE_i386_12
:
751 dump_bytes_hex(pbcfile
, 12);
753 case FpEncodingIEEE_754_16
:
754 dump_bytes_hex(pbcfile
, 16);
757 // This must have been catched before reaching this point
758 throw std::logic_error("Bad number type");
762 void PbcFile::dump_constant_key(ifstream
&pbcfile
)
764 opcode components
= read_opcode(pbcfile
);
765 cout
<< "Key components: " << components
<< '\n';
766 for (opcode i
= 0; i
< components
; ++i
) {
767 cout
<< " " << i
<< ' ';
768 opcode type
= read_opcode(pbcfile
);
769 cout
<< "Type: " << desc_key_type (type
) <<
770 " (0x" << hex
<< type
<< dec
<< ") ";
771 opcode value
= read_opcode(pbcfile
);
772 cout
<< "Value: " << value
<< '\n';
776 void PbcFile::dump_bytes_hex(ifstream
&pbcfile
, opcode length
)
779 for (opcode i
= 0; i
< length
; ++i
) {
780 unsigned char c
= pbcfile
.get();
781 cout
<< setw(2) << setfill('0') << (unsigned int) c
;
786 string
PbcFile::read_cstring(ifstream
&pbcfile
)
790 while ((c
= pbcfile
.get())) {
794 // cstrings are padded with trailing zeroes to opcode size
795 for (opcode l
= r
.size() + 1; l
% opcode_size
; ++l
)
799 throw ReadError("cstring");
803 opcode
PbcFile::read_opcode(ifstream
&pbcfile
)
805 unsigned char buffer
[32]; // Allow 256 bits opcode size
806 pbcfile
.read((char *)buffer
, opcode_size
);
807 if (static_cast<unsigned int>(pbcfile
.gcount()) != opcode_size
)
808 throw ReadError("opcode");
814 for (unsigned int i
= 0; i
< opcode_size
; ++i
) {
816 result
+= buffer
[opcode_size
- 1 - i
];
820 for (unsigned int i
= 0; i
< opcode_size
; ++i
) {
822 result
+= buffer
[i
];
826 // This must have been catched before reaching this point
827 throw std::logic_error("Bad byte order");
832 //**********************************************************************
834 void pbc_checker_main(int argc
, char **argv
)
837 throw runtime_error("Bad args");
840 pbcfile
.read(argv
[1]);
843 //**********************************************************************
845 int main(int argc
, char **argv
)
849 pbc_checker_main(argc
, argv
);
855 cerr
<< "FAILED: " << e
.what() << '\n';
860 // End of pbc_checker.cpp
863 * c-file-style: "parrot"
865 * vim: expandtab shiftwidth=4: