/* * Copyright (c) 2021 Huawei Device Co., Ltd. * * HDF is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * See the LICENSE file in the root of this repository for complete details. */ #include "decompile_gen.h" #include "file.h" #include "logger.h" #include using namespace OHOS::Hardware; DecompileGen::DecompileGen(std::shared_ptr ast, std::string outPutFileName) : ast_(ast) { outPutFileName_ = Util::File::StripSuffix(std::move(outPutFileName)).append(".d.hcs"); Logger().Debug() << "Decompile gen file: " << outPutFileName_; } bool DecompileGen::Init() { file_.open(outPutFileName_, std::ostream::out | std::ostream::binary); if (!file_.is_open()) { Logger().Error() << "Failed to open decompile output file: " << outPutFileName_; return false; } return true; } void DecompileGen::WriteFile(const std::string &str) { file_ << str; } std::string DecompileGen::GetNodeRefPath(uint32_t value) { std::string refPath; std::shared_ptr astObject = ast_->GetAstRoot(); if (astObject == nullptr) { return refPath; } while (astObject->Child() != nullptr) { refPath = astObject->Name() + "."; auto child = astObject->Child(); bool deepIn = false; while (child != nullptr) { if (child->Type() != PARSEROP_CONFNODE) { child = child->Next(); continue; } if (child->GetHash() == value) { return (refPath + child->Name()); } if (value > child->GetHash() && value < (child->GetHash() + child->GetSize())) { astObject = child; deepIn = true; break; } child = child->Next(); } if (!deepIn) { Logger().Error() << "ref unknown node, hash = " << value; break; } } return std::string(); } int32_t DecompileGen::PrintArrayType(const std::shared_ptr &astObj) { WriteFile("["); auto arrayElement = astObj->Child(); if (arrayElement != nullptr) { while (arrayElement->Next()) { if (PrintBaseType(arrayElement) != NOERR) { return EOUTPUT; } WriteFile(", "); arrayElement = arrayElement->Next(); } if (PrintBaseType(arrayElement) != NOERR) { return EOUTPUT; } } WriteFile("]"); return NOERR; } int32_t DecompileGen::PrintBaseType(const std::shared_ptr &astObj) { std::stringstream outStr; std::string refPath; switch (astObj->Type()) { case PARSEROP_UINT8: case PARSEROP_UINT16: case PARSEROP_UINT32: case PARSEROP_UINT64: outStr << "0x" << std::uppercase << std::hex << astObj->IntegerValue(); WriteFile(outStr.str()); break; case PARSEROP_STRING: outStr << "\"" << astObj->StringValue() << "\""; WriteFile(outStr.str()); break; case PARSEROP_NODEREF: refPath = GetNodeRefPath(astObj->IntegerValue()); if (refPath.empty()) { return EOUTPUT; } WriteFile("&" + refPath); break; case PARSEROP_ARRAY: return PrintArrayType(astObj); default: Logger().Error() << "unknown opcode = " << astObj->Type(); return EFAIL; } return NOERR; } int32_t DecompileGen::OutPutWalk(const std::shared_ptr &astObj, int32_t walkDepth) { if (astObj->Type() != PARSEROP_CONFNODE && astObj->Type() != PARSEROP_CONFTERM) { return NOERR; } int ret; std::string tabStr = std::string(TAB_SIZE * walkDepth, ' '); if (walkDepth != 0) { WriteFile(tabStr); } std::string str; switch (astObj->Type()) { case PARSEROP_CONFNODE: str = astObj->Name() + " {\n"; WriteFile(str); if (astObj->Child() == nullptr) { tabStr += "}\n"; WriteFile(tabStr); } break; case PARSEROP_CONFTERM: str = astObj->Name() + " = "; WriteFile(str); ret = PrintBaseType(astObj->Child()); if (ret != NOERR) { return ret; } WriteFile(";\n"); break; default: return EOUTPUT; } return 0; } int32_t DecompileGen::CloseBrace(const std::shared_ptr &astObj, int32_t walkDepth) { if (astObj->Type() != PARSEROP_CONFNODE) { return NOERR; } std::string tabStr = std::string(TAB_SIZE * walkDepth, ' '); if (astObj != ast_->GetAstRoot()) { WriteFile(tabStr + "}\n"); } else { WriteFile("}\n"); } return file_.good() ? NOERR : EOUTPUT; } bool DecompileGen::OutPut() { if (!Init()) { return false; } WriteFile(fileHeader_); if (!ast_->WalkRound( [this](std::shared_ptr ¤t, int32_t walkDepth) -> int32_t { return OutPutWalk(current, walkDepth); }, [this](std::shared_ptr ¤t, int32_t walkDepth) -> int32_t { return CloseBrace(current, walkDepth); })) { return false; } return file_.good(); }