Home | History | Annotate | Download | only in POSIX-DYLD
      1 //===-- DYLDRendezvous.cpp --------------------------------------*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 // C Includes
     11 // C++ Includes
     12 // Other libraries and framework includes
     13 #include "lldb/Core/ArchSpec.h"
     14 #include "lldb/Core/Error.h"
     15 #include "lldb/Core/Log.h"
     16 #include "lldb/Core/Module.h"
     17 #include "lldb/Target/Process.h"
     18 #include "lldb/Target/Target.h"
     19 
     20 #include "DYLDRendezvous.h"
     21 
     22 using namespace lldb;
     23 using namespace lldb_private;
     24 
     25 /// Locates the address of the rendezvous structure.  Returns the address on
     26 /// success and LLDB_INVALID_ADDRESS on failure.
     27 static addr_t
     28 ResolveRendezvousAddress(Process *process)
     29 {
     30     addr_t info_location;
     31     addr_t info_addr;
     32     Error error;
     33     size_t size;
     34 
     35     info_location = process->GetImageInfoAddress();
     36 
     37     if (info_location == LLDB_INVALID_ADDRESS)
     38         return LLDB_INVALID_ADDRESS;
     39 
     40     info_addr = 0;
     41     size = process->DoReadMemory(info_location, &info_addr,
     42                                  process->GetAddressByteSize(), error);
     43     if (size != process->GetAddressByteSize() || error.Fail())
     44         return LLDB_INVALID_ADDRESS;
     45 
     46     if (info_addr == 0)
     47         return LLDB_INVALID_ADDRESS;
     48 
     49     return info_addr;
     50 }
     51 
     52 DYLDRendezvous::DYLDRendezvous(Process *process)
     53     : m_process(process),
     54       m_rendezvous_addr(LLDB_INVALID_ADDRESS),
     55       m_current(),
     56       m_previous(),
     57       m_soentries(),
     58       m_added_soentries(),
     59       m_removed_soentries()
     60 {
     61     // Cache a copy of the executable path
     62     if (m_process)
     63     {
     64         Module *exe_mod = m_process->GetTarget().GetExecutableModulePointer();
     65         if (exe_mod)
     66             exe_mod->GetFileSpec().GetPath(m_exe_path, PATH_MAX);
     67     }
     68 }
     69 
     70 bool
     71 DYLDRendezvous::Resolve()
     72 {
     73     const size_t word_size = 4;
     74     Rendezvous info;
     75     size_t address_size;
     76     size_t padding;
     77     addr_t info_addr;
     78     addr_t cursor;
     79 
     80     address_size = m_process->GetAddressByteSize();
     81     padding = address_size - word_size;
     82 
     83     if (m_rendezvous_addr == LLDB_INVALID_ADDRESS)
     84         cursor = info_addr = ResolveRendezvousAddress(m_process);
     85     else
     86         cursor = info_addr = m_rendezvous_addr;
     87 
     88     if (cursor == LLDB_INVALID_ADDRESS)
     89         return false;
     90 
     91     if (!(cursor = ReadMemory(cursor, &info.version, word_size)))
     92         return false;
     93 
     94     if (!(cursor = ReadMemory(cursor + padding, &info.map_addr, address_size)))
     95         return false;
     96 
     97     if (!(cursor = ReadMemory(cursor, &info.brk, address_size)))
     98         return false;
     99 
    100     if (!(cursor = ReadMemory(cursor, &info.state, word_size)))
    101         return false;
    102 
    103     if (!(cursor = ReadMemory(cursor + padding, &info.ldbase, address_size)))
    104         return false;
    105 
    106     // The rendezvous was successfully read.  Update our internal state.
    107     m_rendezvous_addr = info_addr;
    108     m_previous = m_current;
    109     m_current = info;
    110 
    111     return UpdateSOEntries();
    112 }
    113 
    114 bool
    115 DYLDRendezvous::IsValid()
    116 {
    117     return m_rendezvous_addr != LLDB_INVALID_ADDRESS;
    118 }
    119 
    120 bool
    121 DYLDRendezvous::UpdateSOEntries()
    122 {
    123     SOEntry entry;
    124 
    125     if (m_current.map_addr == 0)
    126         return false;
    127 
    128     // When the previous and current states are consistent this is the first
    129     // time we have been asked to update.  Just take a snapshot of the currently
    130     // loaded modules.
    131     if (m_previous.state == eConsistent && m_current.state == eConsistent)
    132         return TakeSnapshot(m_soentries);
    133 
    134     // If we are about to add or remove a shared object clear out the current
    135     // state and take a snapshot of the currently loaded images.
    136     if (m_current.state == eAdd || m_current.state == eDelete)
    137     {
    138         assert(m_previous.state == eConsistent);
    139         m_soentries.clear();
    140         m_added_soentries.clear();
    141         m_removed_soentries.clear();
    142         return TakeSnapshot(m_soentries);
    143     }
    144     assert(m_current.state == eConsistent);
    145 
    146     // Otherwise check the previous state to determine what to expect and update
    147     // accordingly.
    148     if (m_previous.state == eAdd)
    149         return UpdateSOEntriesForAddition();
    150     else if (m_previous.state == eDelete)
    151         return UpdateSOEntriesForDeletion();
    152 
    153     return false;
    154 }
    155 
    156 bool
    157 DYLDRendezvous::UpdateSOEntriesForAddition()
    158 {
    159     SOEntry entry;
    160     iterator pos;
    161 
    162     assert(m_previous.state == eAdd);
    163 
    164     if (m_current.map_addr == 0)
    165         return false;
    166 
    167     for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next)
    168     {
    169         if (!ReadSOEntryFromMemory(cursor, entry))
    170             return false;
    171 
    172         // Only add shared libraries and not the executable.
    173         // On Linux this is indicated by an empty path in the entry.
    174         // On FreeBSD it is the name of the executable.
    175         if (entry.path.empty() || ::strcmp(entry.path.c_str(), m_exe_path) == 0)
    176             continue;
    177 
    178         pos = std::find(m_soentries.begin(), m_soentries.end(), entry);
    179         if (pos == m_soentries.end())
    180         {
    181             m_soentries.push_back(entry);
    182             m_added_soentries.push_back(entry);
    183         }
    184     }
    185 
    186     return true;
    187 }
    188 
    189 bool
    190 DYLDRendezvous::UpdateSOEntriesForDeletion()
    191 {
    192     SOEntryList entry_list;
    193     iterator pos;
    194 
    195     assert(m_previous.state == eDelete);
    196 
    197     if (!TakeSnapshot(entry_list))
    198         return false;
    199 
    200     for (iterator I = begin(); I != end(); ++I)
    201     {
    202         pos = std::find(entry_list.begin(), entry_list.end(), *I);
    203         if (pos == entry_list.end())
    204             m_removed_soentries.push_back(*I);
    205     }
    206 
    207     m_soentries = entry_list;
    208     return true;
    209 }
    210 
    211 bool
    212 DYLDRendezvous::TakeSnapshot(SOEntryList &entry_list)
    213 {
    214     SOEntry entry;
    215 
    216     if (m_current.map_addr == 0)
    217         return false;
    218 
    219     for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next)
    220     {
    221         if (!ReadSOEntryFromMemory(cursor, entry))
    222             return false;
    223 
    224         // Only add shared libraries and not the executable.
    225         // On Linux this is indicated by an empty path in the entry.
    226         // On FreeBSD it is the name of the executable.
    227         if (entry.path.empty() || ::strcmp(entry.path.c_str(), m_exe_path) == 0)
    228             continue;
    229 
    230         entry_list.push_back(entry);
    231     }
    232 
    233     return true;
    234 }
    235 
    236 addr_t
    237 DYLDRendezvous::ReadMemory(addr_t addr, void *dst, size_t size)
    238 {
    239     size_t bytes_read;
    240     Error error;
    241 
    242     bytes_read = m_process->DoReadMemory(addr, dst, size, error);
    243     if (bytes_read != size || error.Fail())
    244         return 0;
    245 
    246     return addr + bytes_read;
    247 }
    248 
    249 std::string
    250 DYLDRendezvous::ReadStringFromMemory(addr_t addr)
    251 {
    252     std::string str;
    253     Error error;
    254     size_t size;
    255     char c;
    256 
    257     if (addr == LLDB_INVALID_ADDRESS)
    258         return std::string();
    259 
    260     for (;;) {
    261         size = m_process->DoReadMemory(addr, &c, 1, error);
    262         if (size != 1 || error.Fail())
    263             return std::string();
    264         if (c == 0)
    265             break;
    266         else {
    267             str.push_back(c);
    268             addr++;
    269         }
    270     }
    271 
    272     return str;
    273 }
    274 
    275 bool
    276 DYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry)
    277 {
    278     size_t address_size = m_process->GetAddressByteSize();
    279 
    280     entry.clear();
    281 
    282     if (!(addr = ReadMemory(addr, &entry.base_addr, address_size)))
    283         return false;
    284 
    285     if (!(addr = ReadMemory(addr, &entry.path_addr, address_size)))
    286         return false;
    287 
    288     if (!(addr = ReadMemory(addr, &entry.dyn_addr, address_size)))
    289         return false;
    290 
    291     if (!(addr = ReadMemory(addr, &entry.next, address_size)))
    292         return false;
    293 
    294     if (!(addr = ReadMemory(addr, &entry.prev, address_size)))
    295         return false;
    296 
    297     entry.path = ReadStringFromMemory(entry.path_addr);
    298 
    299     return true;
    300 }
    301 
    302 void
    303 DYLDRendezvous::DumpToLog(Log *log) const
    304 {
    305     int state = GetState();
    306 
    307     if (!log)
    308         return;
    309 
    310     log->PutCString("DYLDRendezvous:");
    311     log->Printf("   Address: %" PRIx64, GetRendezvousAddress());
    312     log->Printf("   Version: %" PRIu64, GetVersion());
    313     log->Printf("   Link   : %" PRIx64, GetLinkMapAddress());
    314     log->Printf("   Break  : %" PRIx64, GetBreakAddress());
    315     log->Printf("   LDBase : %" PRIx64, GetLDBase());
    316     log->Printf("   State  : %s",
    317                 (state == eConsistent) ? "consistent" :
    318                 (state == eAdd)        ? "add"        :
    319                 (state == eDelete)     ? "delete"     : "unknown");
    320 
    321     iterator I = begin();
    322     iterator E = end();
    323 
    324     if (I != E)
    325         log->PutCString("DYLDRendezvous SOEntries:");
    326 
    327     for (int i = 1; I != E; ++I, ++i)
    328     {
    329         log->Printf("\n   SOEntry [%d] %s", i, I->path.c_str());
    330         log->Printf("      Base : %" PRIx64, I->base_addr);
    331         log->Printf("      Path : %" PRIx64, I->path_addr);
    332         log->Printf("      Dyn  : %" PRIx64, I->dyn_addr);
    333         log->Printf("      Next : %" PRIx64, I->next);
    334         log->Printf("      Prev : %" PRIx64, I->prev);
    335     }
    336 }
    337