| /* |
| * Copyright (c) 2021 Daniel R. Carvalho |
| * Copyright (c) 2002-2005 The Regents of The University of Michigan |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer; |
| * redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution; |
| * neither the name of the copyright holders nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #ifndef __BASE_LOADER_SYMTAB_HH__ |
| #define __BASE_LOADER_SYMTAB_HH__ |
| |
| #include <functional> |
| #include <iosfwd> |
| #include <map> |
| #include <memory> |
| #include <string> |
| #include <vector> |
| |
| #include "base/compiler.hh" |
| #include "base/types.hh" |
| #include "sim/serialize.hh" |
| |
| namespace gem5 |
| { |
| |
| GEM5_DEPRECATED_NAMESPACE(Loader, loader); |
| namespace loader |
| { |
| |
| struct Symbol |
| { |
| enum class Binding |
| { |
| Global, |
| Local, |
| Weak |
| }; |
| |
| Binding binding; |
| std::string name; |
| Addr address; |
| }; |
| |
| class SymbolTable |
| { |
| public: |
| typedef std::shared_ptr<SymbolTable> SymbolTablePtr; |
| |
| private: |
| /** Vector containing all the symbols in the table. */ |
| typedef std::vector<Symbol> SymbolVector; |
| /** Map addresses to an index into the symbol vector. */ |
| typedef std::multimap<Addr, int> AddrMap; |
| /** Map a symbol name to an index into the symbol vector. */ |
| typedef std::map<std::string, int> NameMap; |
| |
| SymbolVector symbols; |
| AddrMap addrMap; |
| NameMap nameMap; |
| |
| /** |
| * Get the first address larger than the given address, if any. |
| * |
| * @param addr The address to compare against. |
| * @param iter An iterator to the larger-address entry. |
| * @return True if successful; false if no larger addresses exist. |
| */ |
| bool |
| upperBound(Addr addr, AddrMap::const_iterator &iter) const |
| { |
| // find first key *larger* than desired address |
| iter = addrMap.upper_bound(addr); |
| |
| // if very first key is larger, we're out of luck |
| if (iter == addrMap.begin()) |
| return false; |
| |
| return true; |
| } |
| |
| /** |
| * A function that applies an operation on a symbol with respect to a |
| * symbol table. The operation can, for example, simply add the symbol |
| * to the table; modify and insert the symbol; do nothing at all; etc. |
| */ |
| typedef std::function<void(SymbolTable &symtab, |
| const Symbol &symbol)> SymTabOp; |
| |
| /** |
| * Create a derived symbol table by applying an operation on the symbols |
| * of the current table. The current table is not modified. |
| * |
| * @param op The operation to be applied to the new table. |
| * @return The new table. |
| */ |
| SymbolTablePtr |
| operate(SymTabOp op) const |
| { |
| SymbolTablePtr symtab(new SymbolTable); |
| for (const auto &symbol: symbols) |
| op(*symtab, symbol); |
| return symtab; |
| } |
| |
| /** |
| * A function that applies a condition to the symbol provided to decide |
| * whether the symbol is accepted, or if it must be filtered out. |
| */ |
| typedef std::function<bool(const Symbol &symbol)> SymTabFilter; |
| |
| /** |
| * Applies a filter to the symbols of the table to generate a new table. |
| * The filter decides whether the symbols will be inserted in the new |
| * table or not. |
| * |
| * @param filter The filter to be applied. |
| * @return A new table, filtered. |
| */ |
| SymbolTablePtr |
| filter(SymTabFilter filter) const |
| { |
| SymTabOp apply_filter = |
| [filter](SymbolTable &symtab, const Symbol &symbol) { |
| if (filter(symbol)) { |
| symtab.insert(symbol); |
| } |
| }; |
| return operate(apply_filter); |
| } |
| |
| /** |
| * Generate a new table by applying a filter that only accepts the symbols |
| * whose binding matches the given binding. |
| * |
| * @param The binding that must be matched. |
| * @return A new table, filtered by binding. |
| */ |
| SymbolTablePtr |
| filterByBinding(Symbol::Binding binding) const |
| { |
| auto filt = [binding](const Symbol &symbol) { |
| return symbol.binding == binding; |
| }; |
| return filter(filt); |
| } |
| |
| public: |
| typedef SymbolVector::iterator iterator; |
| typedef SymbolVector::const_iterator const_iterator; |
| |
| /** @return An iterator to the beginning of the symbol vector. */ |
| const_iterator begin() const { return symbols.begin(); } |
| |
| /** @return An iterator to the end of the symbol vector. */ |
| const_iterator end() const { return symbols.end(); } |
| |
| /** Clears the table. */ |
| void clear(); |
| |
| /** |
| * Insert a new symbol in the table if it does not already exist. The |
| * symbol must have a defined name. |
| * |
| * @param symbol The symbol to be inserted. |
| * @return True if successful; false if table already contains the symbol. |
| */ |
| bool insert(const Symbol &symbol); |
| |
| /** |
| * Copies the symbols of another table to this table if there are no |
| * common symbols between the tables. |
| * |
| * @param symbol The symbol to be inserted. |
| * @return True if successful; false if tables contain any common symbols. |
| */ |
| bool insert(const SymbolTable &other); |
| |
| /** |
| * Verifies whether the table is empty. |
| * |
| * @return Whether the symbol table is empty. |
| */ |
| bool empty() const { return symbols.empty(); } |
| |
| /** |
| * Generate a new table by applying an offset to the symbols of the |
| * current table. The current table is not modified. |
| * |
| * @param addr_offset The offset to be applied. |
| * @return The new table. |
| */ |
| SymbolTablePtr |
| offset(Addr addr_offset) const |
| { |
| SymTabOp op = |
| [addr_offset](SymbolTable &symtab, const Symbol &symbol) { |
| Symbol sym = symbol; |
| sym.address += addr_offset; |
| symtab.insert(sym); |
| }; |
| return operate(op); |
| } |
| |
| /** |
| * Generate a new table by a mask to the symbols of the current table. |
| * The current table is not modified. |
| * |
| * @param m The mask to be applied. |
| * @return The new table. |
| */ |
| SymbolTablePtr |
| mask(Addr m) const |
| { |
| SymTabOp op = [m](SymbolTable &symtab, const Symbol &symbol) { |
| Symbol sym = symbol; |
| sym.address &= m; |
| symtab.insert(sym); |
| }; |
| return operate(op); |
| } |
| |
| /** |
| * Modify the symbols' name with a given transform function. |
| * |
| * @param func The transform function accepting the reference of the |
| * symbol's name. |
| * @retval SymbolTablePtr A pointer to the modified SymbolTable copy. |
| */ |
| SymbolTablePtr |
| rename(std::function<void(std::string&)> func) const |
| { |
| SymTabOp op = [func](SymbolTable &symtab, const Symbol &symbol) { |
| Symbol sym = symbol; |
| func(sym.name); |
| symtab.insert(sym); |
| }; |
| return operate(op); |
| } |
| |
| /** |
| * Generates a new symbol table containing only global symbols. |
| * |
| * @return The new table. |
| */ |
| SymbolTablePtr |
| globals() const |
| { |
| return filterByBinding(Symbol::Binding::Global); |
| } |
| |
| /** |
| * Generates a new symbol table containing only local symbols. |
| * |
| * @return The new table. |
| */ |
| SymbolTablePtr |
| locals() const |
| { |
| return filterByBinding(Symbol::Binding::Local); |
| } |
| |
| /** |
| * Generates a new symbol table containing only weak symbols. |
| * |
| * @return The new table. |
| */ |
| SymbolTablePtr |
| weaks() const |
| { |
| return filterByBinding(Symbol::Binding::Weak); |
| } |
| |
| /** |
| * Serialize the table's contents. |
| * |
| * @param base The base section. |
| * @param cp The checkpoint to use. |
| */ |
| void serialize(const std::string &base, CheckpointOut &cp) const; |
| |
| /** |
| * Populate the table by unserializing a checkpoint. |
| * |
| * @param base The base section. |
| * @param cp The checkpoint to use. |
| * @param default_binding The binding to be used if an unserialized |
| * symbol's binding is not found. |
| */ |
| void unserialize(const std::string &base, CheckpointIn &cp, |
| Symbol::Binding default_binding=Symbol::Binding::Global); |
| |
| /** |
| * Search for a symbol by its address. Since many symbols can map to the |
| * same address, this function returns the first found. If the symbol is |
| * not found this function returns the end() iterator. |
| * |
| * @param address The address of the symbol being searched for. |
| * @return A const iterator to the symbol. end() if not found. |
| */ |
| const_iterator |
| find(Addr address) const |
| { |
| AddrMap::const_iterator i = addrMap.find(address); |
| if (i == addrMap.end()) |
| return end(); |
| |
| // There are potentially multiple symbols that map to the same |
| // address. For simplicity, just return the first one. |
| return symbols.begin() + i->second; |
| } |
| |
| /** |
| * Search for a symbol by its name. If the symbol is not found this |
| * function returns the end() iterator. |
| * |
| * @param name The name of the symbol being searched for. |
| * @return A const iterator to the symbol. end() if not found. |
| */ |
| const_iterator |
| find(const std::string &name) const |
| { |
| NameMap::const_iterator i = nameMap.find(name); |
| if (i == nameMap.end()) |
| return end(); |
| |
| return symbols.begin() + i->second; |
| } |
| |
| /** |
| * Find the nearest symbol equal to or less than the supplied address |
| * (e.g., the label for the enclosing function). If there is no valid |
| * next address, next_addr is assigned 0. |
| * |
| * @param addr The address to look up. |
| * @param next_addr Address of following symbol (to determine the valid |
| * range of the symbol). |
| * @retval A const_iterator which points to the symbol if found, or end. |
| */ |
| const_iterator |
| findNearest(Addr addr, Addr &next_addr) const |
| { |
| AddrMap::const_iterator i = addrMap.end(); |
| if (!upperBound(addr, i)) |
| return end(); |
| |
| // If there is no next address, make it 0 since 0 is not larger than |
| // any other address, so it is clear that next is not valid |
| if (i == addrMap.end()) { |
| next_addr = 0; |
| } else { |
| next_addr = i->first; |
| } |
| --i; |
| return symbols.begin() + i->second; |
| } |
| |
| /** |
| * Overload for findNearestSymbol() for callers who don't care |
| * about nextaddr. |
| */ |
| const_iterator |
| findNearest(Addr addr) const |
| { |
| AddrMap::const_iterator i = addrMap.end(); |
| if (!upperBound(addr, i)) |
| return end(); |
| |
| --i; |
| return symbols.begin() + i->second; |
| } |
| }; |
| |
| /** |
| * Global unified debugging symbol table (for target). Conceptually |
| * there should be one of these per System object for full system, |
| * and per Process object for non-full-system, but so far one big |
| * global one has worked well enough. |
| */ |
| extern SymbolTable debugSymbolTable; |
| |
| } // namespace loader |
| } // namespace gem5 |
| |
| #endif // __BASE_LOADER_SYMTAB_HH__ |