ObjectContainerBSDArchive.cpp revision 24943d2ee8bfaa7cf5893e4709143924157a5c1e
1//===-- ObjectContainerBSDArchive.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#include "ObjectContainerBSDArchive.h" 11 12#include <ar.h> 13 14#include "lldb/Core/Stream.h" 15#include "lldb/Core/ArchSpec.h" 16#include "lldb/Core/Module.h" 17#include "lldb/Core/PluginManager.h" 18#include "lldb/Core/RegularExpression.h" 19#include "lldb/Host/Mutex.h" 20#include "lldb/Symbol/ObjectFile.h" 21 22using namespace lldb; 23using namespace lldb_private; 24 25 26 27ObjectContainerBSDArchive::Object::Object() : 28 ar_name(), 29 ar_date(0), 30 ar_uid(0), 31 ar_gid(0), 32 ar_mode(0), 33 ar_size(0), 34 ar_file_offset(0), 35 ar_file_size(0) 36{ 37} 38 39void 40ObjectContainerBSDArchive::Object::Clear() 41{ 42 ar_name.Clear(); 43 ar_date = 0; 44 ar_uid = 0; 45 ar_gid = 0; 46 ar_mode = 0; 47 ar_size = 0; 48 ar_file_offset = 0; 49 ar_file_size = 0; 50} 51 52uint32_t 53ObjectContainerBSDArchive::Object::Extract (const DataExtractor& data, uint32_t offset) 54{ 55 size_t ar_name_len = 0; 56 std::string str; 57 char *err; 58 str.assign ((const char *)data.GetData(&offset, 16), 16); 59 if (str.find(AR_EFMT1) == 0) 60 { 61 // If the name is longer than 16 bytes, or contains an embedded space 62 // then it will use this format where the length of the name is 63 // here and the name characters are after this header. 64 ar_name_len = strtoul(str.c_str() + 3, &err, 10); 65 } 66 else 67 { 68 // Strip off any spaces (if the object file name contains spaces it 69 // will use the extended format above). 70 str.erase (str.find(' ')); 71 ar_name.SetCString(str.c_str()); 72 } 73 74 str.assign ((const char *)data.GetData(&offset, 12), 12); 75 ar_date = strtoul(str.c_str(), &err, 10); 76 77 str.assign ((const char *)data.GetData(&offset, 6), 6); 78 ar_uid = strtoul(str.c_str(), &err, 10); 79 80 str.assign ((const char *)data.GetData(&offset, 6), 6); 81 ar_gid = strtoul(str.c_str(), &err, 10); 82 83 str.assign ((const char *)data.GetData(&offset, 8), 8); 84 ar_mode = strtoul(str.c_str(), &err, 8); 85 86 str.assign ((const char *)data.GetData(&offset, 10), 10); 87 ar_size = strtoul(str.c_str(), &err, 10); 88 89 str.assign ((const char *)data.GetData(&offset, 2), 2); 90 if (str == ARFMAG) 91 { 92 if (ar_name_len > 0) 93 { 94 str.assign ((const char *)data.GetData(&offset, ar_name_len), ar_name_len); 95 ar_name.SetCString (str.c_str()); 96 } 97 ar_file_offset = offset; 98 ar_file_size = ar_size - ar_name_len; 99 return offset; 100 } 101 return LLDB_INVALID_INDEX32; 102} 103 104ObjectContainerBSDArchive::Archive::Archive 105( 106 const lldb_private::ArchSpec &arch, 107 const lldb_private::TimeValue &time 108) : 109 m_arch (arch), 110 m_time (time), 111 m_objects() 112{ 113} 114 115ObjectContainerBSDArchive::Archive::~Archive () 116{ 117} 118 119size_t 120ObjectContainerBSDArchive::Archive::ParseObjects (DataExtractor &data) 121{ 122 std::string str; 123 uint32_t offset = 0; 124 str.assign((const char *)data.GetData(&offset, SARMAG), SARMAG); 125 if (str == ARMAG) 126 { 127 Object obj; 128 do 129 { 130 offset = obj.Extract (data, offset); 131 if (offset == LLDB_INVALID_INDEX32) 132 break; 133 uint32_t obj_idx = m_objects.size(); 134 m_objects.push_back(obj); 135 // Insert all of the C strings out of order for now... 136 m_object_name_to_index_map.Append (obj.ar_name.GetCString(), obj_idx); 137 offset += obj.ar_file_size; 138 obj.Clear(); 139 } while (data.ValidOffset(offset)); 140 141 // Now sort all of the object name pointers 142 m_object_name_to_index_map.Sort (); 143 } 144 return m_objects.size(); 145} 146 147ObjectContainerBSDArchive::Object * 148ObjectContainerBSDArchive::Archive::FindObject (const ConstString &object_name) 149{ 150 const UniqueCStringMap<uint32_t>::Entry *match = m_object_name_to_index_map.FindFirstValueForName (object_name.GetCString()); 151 if (match) 152 return &m_objects[match->value]; 153 return NULL; 154} 155 156 157ObjectContainerBSDArchive::Archive::shared_ptr 158ObjectContainerBSDArchive::Archive::FindCachedArchive (const FileSpec &file, const ArchSpec &arch, const TimeValue &time) 159{ 160 Mutex::Locker locker(Archive::GetArchiveCacheMutex ()); 161 shared_ptr archive_sp; 162 Archive::Map &archive_map = Archive::GetArchiveCache (); 163 Archive::Map::iterator pos; 164 for (pos = archive_map.find (file); pos != archive_map.end() && pos->first == file; ++pos) 165 { 166 if (pos->second->GetArchitecture() == arch && 167 pos->second->GetModificationTime() == time) 168 { 169 archive_sp = pos->second; 170 } 171 } 172 return archive_sp; 173} 174 175ObjectContainerBSDArchive::Archive::shared_ptr 176ObjectContainerBSDArchive::Archive::ParseAndCacheArchiveForFile 177( 178 const FileSpec &file, 179 const ArchSpec &arch, 180 const TimeValue &time, 181 DataExtractor &data 182) 183{ 184 shared_ptr archive_sp(new Archive (arch, time)); 185 if (archive_sp) 186 { 187 if (archive_sp->ParseObjects (data) > 0) 188 { 189 Mutex::Locker locker(Archive::GetArchiveCacheMutex ()); 190 Archive::GetArchiveCache().insert(std::make_pair(file, archive_sp)); 191 } 192 else 193 { 194 archive_sp.reset(); 195 } 196 } 197 return archive_sp; 198} 199 200ObjectContainerBSDArchive::Archive::Map & 201ObjectContainerBSDArchive::Archive::GetArchiveCache () 202{ 203 static Archive::Map g_archive_map; 204 return g_archive_map; 205} 206 207Mutex & 208ObjectContainerBSDArchive::Archive::GetArchiveCacheMutex () 209{ 210 static Mutex g_archive_map_mutex (Mutex::eMutexTypeRecursive); 211 return g_archive_map_mutex; 212} 213 214 215void 216ObjectContainerBSDArchive::Initialize() 217{ 218 PluginManager::RegisterPlugin (GetPluginNameStatic(), 219 GetPluginDescriptionStatic(), 220 CreateInstance); 221} 222 223void 224ObjectContainerBSDArchive::Terminate() 225{ 226 PluginManager::UnregisterPlugin (CreateInstance); 227} 228 229 230const char * 231ObjectContainerBSDArchive::GetPluginNameStatic() 232{ 233 return "object-container.bsd-archive"; 234} 235 236const char * 237ObjectContainerBSDArchive::GetPluginDescriptionStatic() 238{ 239 return "BSD Archive object container reader."; 240} 241 242 243ObjectContainer * 244ObjectContainerBSDArchive::CreateInstance 245( 246 Module* module, 247 DataBufferSP& dataSP, 248 const FileSpec *file, 249 addr_t offset, 250 addr_t length) 251{ 252 if (file) 253 { 254 std::string object; 255 256 Archive::shared_ptr archive_sp (Archive::FindCachedArchive (*file, module->GetArchitecture(), module->GetModificationTime())); 257 258 if (archive_sp) 259 { 260 // We already have this archive in our cache, use it 261 std::auto_ptr<ObjectContainerBSDArchive> container_ap(new ObjectContainerBSDArchive (module, dataSP, file, offset, length)); 262 if (container_ap.get()) 263 { 264 container_ap->SetArchive (archive_sp); 265 return container_ap.release(); 266 } 267 } 268 269 if (dataSP) 270 { 271 if (ObjectContainerBSDArchive::MagicBytesMatch(dataSP)) 272 { 273 // Read everything since we need that in order to index all the 274 // objects in the archive 275 dataSP = file->ReadFileContents(offset, length); 276 277 std::auto_ptr<ObjectContainerBSDArchive> container_ap(new ObjectContainerBSDArchive (module, dataSP, file, offset, length)); 278 if (container_ap->ParseHeader()) 279 return container_ap.release(); 280 } 281 } 282 } 283 return NULL; 284} 285 286 287 288bool 289ObjectContainerBSDArchive::MagicBytesMatch (DataBufferSP& dataSP) 290{ 291 DataExtractor data(dataSP, eByteOrderHost, 4); 292 uint32_t offset = 0; 293 const char* armag = (const char* )data.PeekData (offset, sizeof(ar_hdr)); 294 if (armag && ::strncmp(armag, ARMAG, SARMAG) == 0) 295 { 296 armag += offsetof(struct ar_hdr, ar_fmag) + SARMAG; 297 if (strncmp(armag, ARFMAG, 2) == 0) 298 return true; 299 } 300 return false; 301} 302 303ObjectContainerBSDArchive::ObjectContainerBSDArchive 304( 305 Module* module, 306 DataBufferSP& dataSP, 307 const lldb_private::FileSpec *file, 308 lldb::addr_t offset, 309 lldb::addr_t size 310) : 311 ObjectContainer (module, file, offset, size, dataSP), 312 m_archive_sp () 313{ 314} 315void 316ObjectContainerBSDArchive::SetArchive (Archive::shared_ptr &archive_sp) 317{ 318 m_archive_sp = archive_sp; 319} 320 321 322 323ObjectContainerBSDArchive::~ObjectContainerBSDArchive() 324{ 325} 326 327bool 328ObjectContainerBSDArchive::ParseHeader () 329{ 330 if (m_archive_sp.get() == NULL) 331 { 332 if (m_data.GetByteSize() > 0) 333 { 334 m_archive_sp = Archive::ParseAndCacheArchiveForFile (m_file, 335 m_module->GetArchitecture(), 336 m_module->GetModificationTime(), 337 m_data); 338 // The archive might be huge, so clear "m_data" to free up the 339 // memory since it will contain the entire file (possibly more than 340 // one architecture slice). We already have an index of all objects 341 // in the file, so we will be ready to serve up those objects. 342 m_data.Clear(); 343 } 344 } 345 return m_archive_sp.get() != NULL; 346} 347 348void 349ObjectContainerBSDArchive::Dump (Stream *s) const 350{ 351 s->Printf("%.*p: ", (int)sizeof(void*) * 2, this); 352 s->Indent(); 353 const size_t num_archs = GetNumArchitectures(); 354 const size_t num_objects = GetNumObjects(); 355 s->Printf("ObjectContainerBSDArchive, num_archs = %u, num_objects = %u", num_archs, num_objects); 356 uint32_t i; 357 ArchSpec arch; 358 s->IndentMore(); 359 for (i=0; i<num_archs; i++) 360 { 361 s->Indent(); 362 GetArchitectureAtIndex(i, arch); 363 s->Printf("arch[%u] = %s\n", arch.AsCString()); 364 } 365 for (i=0; i<num_objects; i++) 366 { 367 s->Indent(); 368 s->Printf("object[%u] = %s\n", GetObjectNameAtIndex (i)); 369 } 370 s->IndentLess(); 371 s->EOL(); 372} 373 374ObjectFile * 375ObjectContainerBSDArchive::GetObjectFile (const FileSpec *file) 376{ 377 if (m_module->GetObjectName() && m_archive_sp) 378 { 379 Object *object = m_archive_sp->FindObject (m_module->GetObjectName()); 380 if (object) 381 return ObjectFile::FindPlugin (m_module, file, m_offset + object->ar_file_offset, object->ar_file_size); 382 } 383 return NULL; 384} 385 386 387//------------------------------------------------------------------ 388// PluginInterface protocol 389//------------------------------------------------------------------ 390const char * 391ObjectContainerBSDArchive::GetPluginName() 392{ 393 return "object-container.bsd-archive"; 394} 395 396const char * 397ObjectContainerBSDArchive::GetShortPluginName() 398{ 399 return GetPluginNameStatic(); 400} 401 402uint32_t 403ObjectContainerBSDArchive::GetPluginVersion() 404{ 405 return 1; 406} 407 408void 409ObjectContainerBSDArchive::GetPluginCommandHelp (const char *command, Stream *strm) 410{ 411} 412 413Error 414ObjectContainerBSDArchive::ExecutePluginCommand (Args &command, Stream *strm) 415{ 416 Error error; 417 error.SetErrorString("No plug-in command are currently supported."); 418 return error; 419} 420 421Log * 422ObjectContainerBSDArchive::EnablePluginLogging (Stream *strm, Args &command) 423{ 424 return NULL; 425} 426 427 428 429