1/* 2 * Copyright (c) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "symbolTable.h" 17 18#include <fstream> 19#include <iostream> 20#include <util/helpers.h> 21 22namespace panda::es2panda::util { 23const std::string SymbolTable::FIRST_LEVEL_SEPERATOR = "|"; 24const std::string SymbolTable::SECOND_LEVEL_SEPERATOR = ";"; 25const size_t FUNCTION_ITEM_NUMBER = 3; 26const size_t MODULE_ITEM_NUMBER = 1; 27 28bool SymbolTable::Initialize(int targetApiVersion, std::string targetApiSubVersion) 29{ 30 targetApiVersion_ = targetApiVersion; 31 targetApiSubVersion_ = targetApiSubVersion; 32 if (!symbolTable_.empty() && !ReadSymbolTable(symbolTable_)) { 33 std::cerr << "Failed to open the symbol table file'" << std::endl; 34 return false; 35 } 36 37 if (!dumpSymbolTable_.empty()) { 38 std::fstream fs; 39 fs.open(panda::os::file::File::GetExtendedFilePath(dumpSymbolTable_), 40 std::ios_base::out | std::ios_base::trunc); 41 if (!fs.is_open()) { 42 std::cerr << "Failed to create or open the output symbol table file '" 43 << dumpSymbolTable_ << "' during symbol table initialization." << std::endl 44 << "This error could be due to invalid file path, lack of write permissions, " 45 << "or the file being in use by another process." << std::endl; 46 return false; 47 } 48 fs.close(); 49 } 50 51 return true; 52} 53 54void SymbolTable::ReadRecordHashFunctionNames(const std::string &recordName, const std::string &funcInternalName, 55 const std::string &specialFuncIndex) 56{ 57 auto recordHashFunctionNames = originRecordHashFunctionNames_.find(recordName); 58 if (specialFuncIndex == "0") { 59 // 0: not anonymous, special or duplicate function 60 if (recordHashFunctionNames == originRecordHashFunctionNames_.end()) { 61 std::unordered_map<std::string, std::string> functionIndexNameMap {}; 62 originRecordHashFunctionNames_.insert({recordName, functionIndexNameMap}); 63 } 64 } else { 65 if (recordHashFunctionNames != originRecordHashFunctionNames_.end()) { 66 recordHashFunctionNames->second.insert({specialFuncIndex, funcInternalName}); 67 } else { 68 std::unordered_map<std::string, std::string> functionIndexNameMap {{specialFuncIndex, funcInternalName}}; 69 originRecordHashFunctionNames_.insert({recordName, functionIndexNameMap}); 70 } 71 } 72} 73 74bool SymbolTable::ReadSymbolTable(const std::string &symbolTable) 75{ 76 std::ifstream ifs; 77 std::string line; 78 ifs.open(panda::os::file::File::GetExtendedFilePath(symbolTable)); 79 if (!ifs.is_open()) { 80 std::cerr << "Failed to open the symbol table file '" 81 << symbolTable << "' during symbol table reading." << std::endl 82 << "Please check if the file exists, the path is correct, " 83 << "and your program has the necessary permissions to access the file." << std::endl; 84 return false; 85 } 86 87 while (std::getline(ifs, line)) { 88 auto itemList = GetStringItems(line, FIRST_LEVEL_SEPERATOR); 89 90 if (itemList.size() == FUNCTION_ITEM_NUMBER) { 91 // read function info 92 struct OriginFunctionInfo info(&allocator_); 93 auto funcItems = GetStringItems(itemList[0], SECOND_LEVEL_SEPERATOR); 94 auto classItems = GetStringItems(itemList[1], SECOND_LEVEL_SEPERATOR); 95 auto lexItems = GetStringItems(itemList[2], SECOND_LEVEL_SEPERATOR); 96 97 info.recordName = funcItems[0].substr(0, funcItems[0].find_last_of(".")); 98 info.funcInternalName = funcItems[1]; 99 // 2: use the third element of the function as the hash of the function 100 info.funcHash = funcItems[2]; 101 102 // 2 is to process each class name and its corresponding hash value 103 for (size_t i = 0; i < classItems.size(); i = i + 2) { 104 info.classHash.insert(std::pair<std::string, std::string>(classItems[i], classItems[i + 1])); 105 } 106 // 3 is to process a complete lexical environment entry 107 for (size_t i = 0; i < lexItems.size(); i = i + 3) { 108 auto name = std::string(lexItems[i]); 109 auto slot = std::atoi(std::string(lexItems[i + 1]).c_str()); 110 auto type = std::atoi(std::string(lexItems[i + 2]).c_str()); 111 info.lexenv.insert({slot, std::pair<std::string, int>(name, type)}); 112 } 113 114 originFunctionInfo_.insert(std::pair<std::string, OriginFunctionInfo>(info.funcInternalName, info)); 115 if (util::Helpers::IsDefaultApiVersion(targetApiVersion_, targetApiSubVersion_)) { 116 // index of function in its record's special function array 117 std::string specialFuncIndex{funcItems[3]}; 118 ReadRecordHashFunctionNames(info.recordName, info.funcInternalName, specialFuncIndex); 119 } 120 } else if (itemList.size() == MODULE_ITEM_NUMBER) { 121 // read module info 122 auto moduleItems = GetStringItems(itemList[0], SECOND_LEVEL_SEPERATOR); 123 originModuleInfo_.insert(std::pair<std::string, std::string>(moduleItems[0], moduleItems[1])); 124 } else { 125 std::cerr << "Failed to read the symbol table line: '" << line 126 << "' from the symbol table file '" << symbolTable << "' due to unrecognized format." << std::endl 127 << "Please verify the format of the symbol table." << std::endl; 128 } 129 } 130 return true; 131} 132 133void SymbolTable::FillSymbolTable(const std::stringstream &content) 134{ 135 std::lock_guard<std::mutex> lock(m_); 136 symbolTableContent_ << content.rdbuf(); 137} 138 139void SymbolTable::WriteSymbolTable() 140{ 141 std::fstream fs; 142 fs.open(panda::os::file::File::GetExtendedFilePath(dumpSymbolTable_), 143 std::ios_base::app | std::ios_base::in); 144 if (fs.is_open()) { 145 fs << symbolTableContent_.str(); 146 fs.close(); 147 } 148} 149 150std::vector<std::string_view> SymbolTable::GetStringItems(std::string_view input, const std::string &separator) 151{ 152 std::vector<std::string_view> items; 153 size_t curPos = 0; 154 size_t lastPos = 0; 155 156 while ((curPos = input.find(separator, lastPos)) != std::string_view::npos) { 157 auto token = input.substr(lastPos, curPos - lastPos); 158 if (!token.empty()) { 159 items.push_back(token); 160 } 161 lastPos = curPos + separator.size(); 162 } 163 164 auto tail = input.substr(lastPos); 165 if (!tail.empty()) { 166 items.push_back(tail); 167 } 168 169 return items; 170} 171} // namespace panda::es2panda::util