87 #include "decompiler.h"
88 #include "../submodules/CoreLibrary/CoreLibrary/utils.h"
91 using namespace std::chrono;
92 using namespace r_code;
97 static std::string make_suffix(uint32 value) {
101 uint32 lowest = value % 26;
102 result = (char)(
'a' + lowest) + result;
106 }
while (value != 0);
111 Decompiler::Decompiler() : out_stream_(NULL), current_object_(NULL), metadata_(NULL), image_(NULL), in_hlp_(false) {
116 Decompiler::~Decompiler() {
122 std::string Decompiler::get_variable_name(uint16 index,
bool postfix) {
124 unordered_map<uint16, std::string>::iterator it = variable_names_.find(index);
125 if (it == variable_names_.end()) {
127 std::string s =
"v" + std::to_string(last_variable_id_++);
128 variable_names_[index] = s;
131 out_stream_->insert(index, s);
133 return s.substr(0, s.length() - 1);
139 std::string Decompiler::get_hlp_variable_name(uint16 index) {
141 std::string s =
"v" + std::to_string(index);
147 std::string Decompiler::get_object_name(uint16 index) {
150 unordered_map<uint16, std::string>::iterator it = object_names_.find(index);
151 if (it == object_names_.end()) {
153 s =
"unknown-object";
161 metadata_ = metadata;
162 time_reference_ = Timestamp(seconds(0));
164 partial_decompilation_ =
false;
165 ignore_named_objects_ =
false;
168 for (uint16 i = 0; i < metadata->classes_by_opcodes_.size(); ++i) {
170 Class *c = metadata->get_class(i);
171 std::string class_name = c->str_opcode;
172 size_t p = class_name.find(
"mk.");
173 if (p != std::string::npos)
174 renderers_[i] = &Decompiler::write_marker;
175 else if (class_name ==
"pred")
176 renderers_[i] = &Decompiler::write_marker;
177 else if (class_name ==
"grp")
178 renderers_[i] = &Decompiler::write_group;
179 else if (class_name ==
"ipgm" || class_name ==
"icpp_pgm")
180 renderers_[i] = &Decompiler::write_ipgm;
181 else if (class_name ==
"pgm" || class_name ==
"|pgm")
182 renderers_[i] = &Decompiler::write_pgm;
183 else if (class_name ==
"icmd")
184 renderers_[i] = &Decompiler::write_icmd;
185 else if (class_name ==
"cmd")
186 renderers_[i] = &Decompiler::write_cmd;
187 else if (class_name ==
"fact" || class_name ==
"|fact")
188 renderers_[i] = &Decompiler::write_fact;
189 else if (class_name ==
"cst" || class_name ==
"mdl")
190 renderers_[i] = &Decompiler::write_hlp;
191 else if (class_name ==
"icst" || class_name ==
"imdl")
192 renderers_[i] = &Decompiler::write_ihlp;
194 renderers_[i] = &Decompiler::write_expression;
198 uint32 Decompiler::decompile(
r_comp::Image *image, std::ostringstream *stream, Timestamp time_reference,
bool ignore_named_objects) {
200 ignore_named_objects_ = ignore_named_objects;
202 uint32 object_count = decompile_references(image);
204 for (uint16 i = 0; i < image->code_segment_.objects_.size(); ++i)
205 decompile_object(i, stream, time_reference);
210 uint32 Decompiler::decompile(
r_comp::Image *image, std::ostringstream *stream, Timestamp time_reference, vector<SysObject *> &imported_objects,
211 bool include_oid,
bool include_label,
bool include_views) {
213 partial_decompilation_ =
true;
214 ignore_named_objects_ =
true;
215 imported_objects_ = imported_objects;
217 uint32 object_count = decompile_references(image);
219 for (uint16 i = 0; i < image->code_segment_.objects_.size(); ++i)
220 decompile_object(i, stream, time_reference, include_oid, include_label, include_views);
225 uint32 Decompiler::decompile_references(
r_comp::Image *image, unordered_map<uint16, std::string>* object_names) {
229 for (
auto entry = object_names->begin(); entry != object_names->end(); ++entry) {
230 object_names_[entry->first] = entry->second;
231 object_indices_[entry->second] = entry->first;
235 unordered_map<const Class *, uint16> object_ID_per_class;
236 unordered_map<std::string, Class>::const_iterator it;
237 for (it = metadata_->sys_classes_.begin(); it != metadata_->sys_classes_.end(); ++it)
238 object_ID_per_class[&(it->second)] = 0;
246 for (uint16 i = 0; i < image->code_segment_.objects_.size(); ++i) {
249 unordered_map<uint32, std::string>::const_iterator n = image->object_names_.symbols_.find(sys_object->oid_);
250 if (n != image->object_names_.symbols_.end()) {
253 named_objects_.insert(sys_object->oid_);
255 if (object_names_[i] !=
"" && object_names_[i] != s)
260 object_names_[i] = s;
261 object_indices_[s] = i;
265 regex verticalBarRegex(
"\\|");
267 for (uint16 i = 0; i < image->code_segment_.objects_.size(); ++i) {
270 unordered_map<uint32, std::string>::const_iterator n = image->object_names_.symbols_.find(sys_object->oid_);
271 if (n != image->object_names_.symbols_.end())
274 if (object_names_.find(i) != object_names_.end())
278 Class *c = metadata_->get_class(sys_object->code_[0].asOpcode());
279 string className = c->str_opcode;
281 replace(className.begin(), className.end(),
'.',
'_');
284 className = regex_replace(className, verticalBarRegex,
"anti_");
286 if (sys_object->oid_ != UNDEFINED_OID)
288 s = className +
"_" + std::to_string(sys_object->oid_);
291 uint16 last_object_ID = object_ID_per_class[c];
292 object_ID_per_class[c] = last_object_ID + 1;
293 s = className + std::to_string(last_object_ID);
296 if (object_indices_.find(s) != object_indices_.end()) {
299 for (uint32 value = 1;
true; ++value) {
300 std::string new_s = s + make_suffix(value);
301 if (object_indices_.find(new_s) == object_indices_.end()) {
308 object_names_[i] = s;
309 object_indices_[s] = i;
312 closing_set_ =
false;
314 return image->code_segment_.objects_.size();
317 void Decompiler::decompile_object(
318 uint16 object_index, std::ostringstream *stream, Timestamp time_reference,
bool include_oid,
319 bool include_label,
bool include_views) {
323 else if (out_stream_->stream_ != stream) {
329 time_reference_ = time_reference;
331 variable_names_.clear();
332 last_variable_id_ = 0;
334 current_object_ = image_->code_segment_.objects_[object_index];
336 uint16 read_index = 0;
337 bool after_tail_wildcard =
false;
340 if (!partial_decompilation_ && ignore_named_objects_) {
342 if (named_objects_.find(sys_object->oid_) != named_objects_.end())
347 bool imported =
false;
348 for (uint32 i = 0; i < imported_objects_.size(); ++i) {
350 if (sys_object == imported_objects_[i]) {
359 if (named_objects_.find(sys_object->oid_) != named_objects_.end())
362 *out_stream_ <<
"imported";
366 if (sys_object->oid_ != UNDEFINED_OID)
367 *out_stream_ << sys_object->oid_;
368 #ifdef WITH_DETAIL_OID
369 *out_stream_ <<
"(" << sys_object->detail_oid_ <<
") ";
371 if (sys_object->oid_ != UNDEFINED_OID)
379 std::string s = object_names_[object_index];
384 horizontal_set_ =
false;
386 (this->*renderers_[current_object_->code_[read_index].asOpcode()])(read_index);
389 uint16 view_count = sys_object->views_.size();
392 *out_stream_ <<
" []";
393 for (uint16 i = 0; i < view_count; ++i) {
396 current_object_ = sys_object->views_[i];
397 write_view(0, current_object_->code_[0].getAtomCount());
401 *out_stream_ <<
" |[]";
407 void Decompiler::decompile_object(
const std::string object_name, std::ostringstream *stream, Timestamp time_reference) {
409 decompile_object(object_indices_[object_name], stream, time_reference);
412 void Decompiler::write_indent(uint16 i) {
414 *out_stream_ << NEWLINE;
416 for (uint16 j = 0; j < indents_; j++)
420 void Decompiler::write_expression_head(uint16 read_index) {
422 switch (current_object_->code_[read_index].getDescriptor()) {
424 *out_stream_ << metadata_->operator_names_[current_object_->code_[read_index].asOpcode()];
428 *out_stream_ << metadata_->class_names_[current_object_->code_[read_index].asOpcode()];
430 case Atom::INSTANTIATED_PROGRAM:
431 case Atom::INSTANTIATED_INPUT_LESS_PROGRAM:
432 case Atom::INSTANTIATED_ANTI_PROGRAM:
433 *out_stream_ <<
"ipgm";
435 case Atom::INSTANTIATED_CPP_PROGRAM:
436 *out_stream_ <<
"icpp_pgm";
438 case Atom::COMPOSITE_STATE:
439 *out_stream_ <<
"cst";
442 *out_stream_ <<
"mdl";
445 *out_stream_ <<
"grp";
448 *out_stream_ <<
"undefined-class";
453 void Decompiler::write_expression_tail(uint16 read_index) {
455 uint16 arity = current_object_->code_[read_index].getAtomCount();
456 bool after_tail_wildcard =
false;
458 for (uint16 i = 0; i < arity; ++i) {
460 if (after_tail_wildcard)
461 write_any(++read_index, after_tail_wildcard);
466 closing_set_ =
false;
467 if (!horizontal_set_)
468 write_indent(indents_);
474 write_any(++read_index, after_tail_wildcard);
479 void Decompiler::write_expression(uint16 read_index) {
483 closing_set_ =
false;
484 write_indent(indents_);
486 out_stream_->push(
'(', read_index);
487 write_expression_head(read_index);
488 write_expression_tail(read_index);
491 closing_set_ =
false;
492 write_indent(indents_);
497 void Decompiler::write_group(uint16 read_index) {
501 closing_set_ =
false;
502 write_indent(indents_);
504 out_stream_->push(
'(', read_index);
505 write_expression_head(read_index);
506 write_expression_tail(read_index);
509 closing_set_ =
false;
510 write_indent(indents_);
515 void Decompiler::write_marker(uint16 read_index) {
518 horizontal_set_ =
true;
521 closing_set_ =
false;
522 write_indent(indents_);
524 out_stream_->push(
'(', read_index);
525 write_expression_head(read_index);
526 write_expression_tail(read_index);
529 closing_set_ =
false;
530 write_indent(indents_);
534 horizontal_set_ =
false;
537 void Decompiler::write_pgm(uint16 read_index) {
541 closing_set_ =
false;
542 write_indent(indents_);
544 out_stream_->push(
'(', read_index);
545 write_expression_head(read_index);
546 write_expression_tail(read_index);
549 closing_set_ =
false;
550 write_indent(indents_);
556 void Decompiler::write_ipgm(uint16 read_index) {
560 closing_set_ =
false;
561 write_indent(indents_);
563 out_stream_->push(
'(', read_index);
564 write_expression_head(read_index);
565 write_expression_tail(read_index);
568 closing_set_ =
false;
569 write_indent(indents_);
574 void Decompiler::write_hlp(uint16 read_index) {
579 closing_set_ =
false;
580 write_indent(indents_);
582 out_stream_->push(
'(', read_index);
583 write_expression_head(read_index);
586 uint16 arity = current_object_->code_[read_index].getAtomCount();
587 bool after_tail_wildcard =
false;
589 for (uint16 i = 0; i < arity; ++i) {
591 if (after_tail_wildcard)
592 write_any(++read_index, after_tail_wildcard);
597 closing_set_ =
false;
602 write_indent(indents_);
605 if (!(i == 0 || i == 1))
608 hlp_postfix_ =
false;
609 bool save_horizontal_set = horizontal_set_;
610 if (i == 0 || i == 4)
612 horizontal_set_ =
true;
613 write_any(++read_index, after_tail_wildcard);
615 horizontal_set_ = save_horizontal_set;
618 *out_stream_ << (i == 0 || i >= 4 ?
' ' : NEWLINE);
624 closing_set_ =
false;
625 write_indent(indents_);
631 void Decompiler::write_ihlp(uint16 read_index) {
634 horizontal_set_ =
true;
637 closing_set_ =
false;
638 write_indent(indents_);
640 out_stream_->push(
'(', read_index);
641 write_expression_head(read_index);
642 write_expression_tail(read_index);
645 closing_set_ =
false;
646 write_indent(indents_);
650 horizontal_set_ =
false;
653 void Decompiler::write_icmd(uint16 read_index) {
657 closing_set_ =
false;
658 write_indent(indents_);
660 out_stream_->push(
'(', read_index);
661 write_expression_head(read_index);
663 uint16 write_as_view_index = 0;
664 if (current_object_->code_[read_index + 1].asOpcode() == metadata_->classes_.find(
"_inj")->second.atom_.asOpcode()) {
666 uint16 arg_set_index = current_object_->code_[read_index + 2].asIndex();
667 write_as_view_index = current_object_->code_[arg_set_index + 2].asIndex();
670 uint16 arity = current_object_->code_[read_index].getAtomCount();
671 bool after_tail_wildcard =
false;
673 for (uint16 i = 0; i < arity; ++i) {
675 if (after_tail_wildcard)
676 write_any(++read_index, after_tail_wildcard);
681 closing_set_ =
false;
682 write_indent(indents_);
686 write_any(++read_index, after_tail_wildcard, write_as_view_index);
692 closing_set_ =
false;
693 write_indent(indents_);
698 void Decompiler::write_cmd(uint16 read_index) {
701 horizontal_set_ =
true;
704 closing_set_ =
false;
705 write_indent(indents_);
707 out_stream_->push(
'(', read_index);
708 write_expression_head(read_index);
709 write_expression_tail(read_index);
712 closing_set_ =
false;
713 write_indent(indents_);
717 horizontal_set_ =
false;
720 void Decompiler::write_fact(uint16 read_index) {
723 horizontal_set_ =
true;
726 closing_set_ =
false;
727 write_indent(indents_);
729 out_stream_->push(
'(', read_index);
730 write_expression_head(read_index);
731 write_expression_tail(read_index);
734 closing_set_ =
false;
735 write_indent(indents_);
738 horizontal_set_ =
false;
741 void Decompiler::write_view(uint16 read_index, uint16 arity) {
743 if (arity > VIEW_CODE_MAX_SIZE || arity <= 1) {
745 *out_stream_ <<
"nil";
749 bool after_tail_wildcard =
false;
752 for (uint16 j = 1; j <= arity; ++j) {
754 write_any(read_index + j, after_tail_wildcard);
761 void Decompiler::write_set(uint16 read_index, uint16 write_as_view_index) {
763 uint16 arity = current_object_->code_[read_index].getAtomCount();
764 bool after_tail_wildcard =
false;
768 out_stream_->push(
'[', read_index);
769 write_any(++read_index, after_tail_wildcard);
771 }
else if (write_as_view_index > 0 && write_as_view_index == read_index)
772 write_view(read_index, arity);
773 else if (horizontal_set_) {
775 out_stream_->push(
'[', read_index);
776 for (uint16 i = 0; i < arity; ++i) {
780 if (after_tail_wildcard)
781 write_any(++read_index, after_tail_wildcard);
783 write_any(++read_index, after_tail_wildcard, write_as_view_index);
789 out_stream_->push(
"[]", read_index);
791 for (uint16 i = 0; i < arity; ++i) {
793 if (after_tail_wildcard)
794 write_any(++read_index, after_tail_wildcard);
797 write_indent(indents_);
798 write_any(++read_index, after_tail_wildcard, write_as_view_index);
806 void Decompiler::write_any(uint16 read_index,
bool &after_tail_wildcard, uint16 write_as_view_index) {
808 Atom a = current_object_->code_[read_index];
812 if (a.atom_ == 0x3FFFFFFF)
813 out_stream_->push(
"|nb", read_index);
814 else if (a == Atom::PlusInfinity())
815 out_stream_->push(
"forever", read_index);
818 *out_stream_ << std::dec;
819 out_stream_->push(a.asFloat(), read_index);
826 switch (a.getDescriptor()) {
829 if (a.asCastOpcode() == 0x0FFE)
830 out_stream_->push(
':', read_index);
833 std::string s = get_hlp_variable_name(a.asIndex());
834 out_stream_->push(s, read_index);
837 case Atom::ASSIGN_PTR:
839 out_stream_->push(get_hlp_variable_name(a.asAssignmentIndex()), read_index);
841 case Atom::CODE_VL_PTR:
845 atom = current_object_->code_[index];
846 while (atom.getDescriptor() == Atom::I_PTR) {
848 index = atom.asIndex();
849 atom = current_object_->code_[index];
851 if (index < read_index) {
853 std::string s = get_variable_name(index, atom.getDescriptor() != Atom::WILDCARD);
854 out_stream_->push(s, read_index);
857 switch (atom.getDescriptor()) {
861 case Atom::INSTANTIATED_PROGRAM:
862 case Atom::INSTANTIATED_INPUT_LESS_PROGRAM:
863 case Atom::INSTANTIATED_ANTI_PROGRAM:
864 case Atom::INSTANTIATED_CPP_PROGRAM:
865 case Atom::COMPOSITE_STATE:
868 (this->*renderers_[atom.asOpcode()])(index);
872 if (atom.readsAsNil())
874 out_stream_->push(horizontal_set_ ?
"[]" :
"|[]", read_index);
876 write_set(index, write_as_view_index);
879 if (atom.readsAsNil())
880 out_stream_->push(
"|st", read_index);
883 std::string s = Utils::GetString(¤t_object_->code_[index]);
884 *out_stream_ <<
'\"' << s <<
'\"';
887 case Atom::TIMESTAMP:
888 if (atom.readsAsNil())
889 out_stream_->push(
"|ts", read_index);
891 out_stream_->push(Utils::ToString_s_ms_us(Utils::GetTimestamp(¤t_object_->code_[index]), time_reference_), read_index);
894 out_stream_->push(Utils::ToString_us(Utils::GetDuration(¤t_object_->code_[index])), read_index);
899 uint16 member_count = atom.getAtomCount();
900 atom = current_object_->code_[index + 1];
901 switch (atom.getDescriptor()) {
903 out_stream_->push(
"this", read_index);
904 opcode = metadata_->sys_classes_[
"ipgm"].atom_.asOpcode();
906 case Atom::CODE_VL_PTR: {
908 uint8 cast_opcode = atom.asCastOpcode();
909 while (current_object_->code_[atom.asIndex()].getDescriptor() == Atom::I_PTR)
910 atom = current_object_->code_[atom.asIndex()];
911 out_stream_->push(get_variable_name(atom.asIndex(), current_object_->code_[atom.asIndex()].getDescriptor() != Atom::WILDCARD), read_index);
912 if (cast_opcode == 0xFF) {
914 if (current_object_->code_[atom.asIndex()].getDescriptor() == Atom::WILDCARD)
915 opcode = current_object_->code_[atom.asIndex()].asOpcode();
917 opcode = current_object_->code_[atom.asIndex()].asOpcode();
919 opcode = cast_opcode;
922 uint32 object_index = current_object_->references_[atom.asIndex()];
923 out_stream_->push(get_object_name(object_index), read_index);
924 opcode = image_->code_segment_.objects_[object_index]->code_[0].asOpcode();
927 out_stream_->push(
"unknown-cptr-lead-type", read_index);
931 Class embedding_class = metadata_->classes_by_opcodes_[opcode];
932 for (uint16 i = 2; i <= member_count; ++i) {
934 std::string member_name;
935 atom = current_object_->code_[index + i];
936 switch (atom.getDescriptor()) {
947 member_name = embedding_class.get_member_name(atom.asIndex());
948 if (i < member_count)
949 embedding_class = *embedding_class.get_member_class(metadata_, member_name);
952 *out_stream_ <<
'.' << member_name;
954 if (member_name ==
"vw") {
956 atom = current_object_->code_[index + member_count];
958 if (embedding_class.str_opcode ==
"grp")
959 view_class = metadata_->classes_.find(
"grp_view")->second;
960 else if (embedding_class.str_opcode ==
"ipgm" ||
961 embedding_class.str_opcode ==
"icpp_pgm" ||
962 embedding_class.str_opcode ==
"mdl" ||
963 embedding_class.str_opcode ==
"cst")
964 view_class = metadata_->classes_.find(
"pgm_view")->second;
966 view_class = metadata_->classes_.find(
"view")->second;
967 member_name = view_class.get_member_name(atom.asIndex());
968 *out_stream_ <<
'.' << member_name;
974 out_stream_->push(
"undefined-structural-atom-or-reference", read_index);
979 out_stream_->push(get_object_name(current_object_->references_[a.asIndex()]), read_index);
982 out_stream_->push(
"this", read_index);
985 out_stream_->push(
"nil", read_index);
989 out_stream_->push(
"|bl", read_index);
992 *out_stream_ << std::boolalpha;
993 out_stream_->push(a.asBoolean(), read_index);
997 if (after_tail_wildcard)
1000 out_stream_->push(
':', read_index);
1002 case Atom::T_WILDCARD:
1003 out_stream_->push(
"::", read_index);
1004 after_tail_wildcard =
true;
1008 out_stream_->push(
"|sid", read_index);
1011 out_stream_->push(
"0x", read_index);
1012 *out_stream_ << std::hex;
1013 *out_stream_ << a.atom_;
1018 out_stream_->push(
"|did", read_index);
1021 out_stream_->push(
"0x", read_index);
1022 *out_stream_ << std::hex;
1023 *out_stream_ << a.atom_;
1026 case Atom::DEVICE_FUNCTION:
1028 out_stream_->push(
"|fid", read_index);
1030 out_stream_->push(metadata_->function_names_[a.asOpcode()], read_index);
1033 out_stream_->push(
"vw", read_index);
1036 out_stream_->push(
"mks", read_index);
1039 out_stream_->push(
"vws", read_index);
1043 out_stream_->push(
"0x", read_index);
1044 *out_stream_ << std::hex;
1045 *out_stream_ << a.atom_;