blob: 97aed1a323b9552aa7cc24d152d74903542e0ac4 [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- 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"
Greg Claytonaecb12b2012-01-09 23:59:30 +000018#include "lldb/Core/Timer.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000019#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);
Eli Friedman04e6ba72010-06-10 04:56:00 +000059 if (str.find("#1/") == 0)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000060 {
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 ();
Greg Clayton762f7132011-09-18 18:59:15 +0000163 Archive::Map::iterator pos = archive_map.find (file);
164 // Don't cache a value for "archive_map.end()" below since we might
165 // delete an archive entry...
166 while (pos != archive_map.end() && pos->first == file)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000167 {
Sean Callananbf4b7be2012-12-13 22:07:14 +0000168 if (pos->second->GetArchitecture().IsCompatibleMatch(arch))
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000169 {
Greg Clayton762f7132011-09-18 18:59:15 +0000170 if (pos->second->GetModificationTime() == time)
171 {
172 return pos->second;
173 }
174 else
175 {
176 // We have a file at the same path with the same architecture
177 // whose modification time doesn't match. It doesn't make sense
178 // for us to continue to use this BSD archive since we cache only
179 // the object info which consists of file time info and also the
180 // file offset and file size of any contianed objects. Since
181 // this information is now out of date, we won't get the correct
182 // information if we go and extract the file data, so we should
183 // remove the old and outdated entry.
184 archive_map.erase (pos);
185 pos = archive_map.find (file);
186 continue;
187 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000188 }
Greg Clayton762f7132011-09-18 18:59:15 +0000189 ++pos;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000190 }
191 return archive_sp;
192}
193
194ObjectContainerBSDArchive::Archive::shared_ptr
195ObjectContainerBSDArchive::Archive::ParseAndCacheArchiveForFile
196(
197 const FileSpec &file,
198 const ArchSpec &arch,
199 const TimeValue &time,
200 DataExtractor &data
201)
202{
203 shared_ptr archive_sp(new Archive (arch, time));
204 if (archive_sp)
205 {
206 if (archive_sp->ParseObjects (data) > 0)
207 {
208 Mutex::Locker locker(Archive::GetArchiveCacheMutex ());
209 Archive::GetArchiveCache().insert(std::make_pair(file, archive_sp));
210 }
211 else
212 {
213 archive_sp.reset();
214 }
215 }
216 return archive_sp;
217}
218
219ObjectContainerBSDArchive::Archive::Map &
220ObjectContainerBSDArchive::Archive::GetArchiveCache ()
221{
222 static Archive::Map g_archive_map;
223 return g_archive_map;
224}
225
226Mutex &
227ObjectContainerBSDArchive::Archive::GetArchiveCacheMutex ()
228{
229 static Mutex g_archive_map_mutex (Mutex::eMutexTypeRecursive);
230 return g_archive_map_mutex;
231}
232
233
234void
235ObjectContainerBSDArchive::Initialize()
236{
237 PluginManager::RegisterPlugin (GetPluginNameStatic(),
238 GetPluginDescriptionStatic(),
239 CreateInstance);
240}
241
242void
243ObjectContainerBSDArchive::Terminate()
244{
245 PluginManager::UnregisterPlugin (CreateInstance);
246}
247
248
249const char *
250ObjectContainerBSDArchive::GetPluginNameStatic()
251{
252 return "object-container.bsd-archive";
253}
254
255const char *
256ObjectContainerBSDArchive::GetPluginDescriptionStatic()
257{
258 return "BSD Archive object container reader.";
259}
260
261
262ObjectContainer *
263ObjectContainerBSDArchive::CreateInstance
264(
Greg Claytone72dfb32012-02-24 01:59:29 +0000265 const lldb::ModuleSP &module_sp,
Greg Claytonfad9eef2011-08-03 04:39:36 +0000266 DataBufferSP& data_sp,
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000267 const FileSpec *file,
Greg Claytonfa8c0042012-01-12 01:21:31 +0000268 addr_t offset,
269 addr_t length)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000270{
Greg Clayton44435ed2012-01-12 05:25:17 +0000271 DataExtractor data;
272 data.SetData (data_sp, offset, length);
273 if (file && data_sp && ObjectContainerBSDArchive::MagicBytesMatch(data))
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000274 {
Greg Claytonaecb12b2012-01-09 23:59:30 +0000275 Timer scoped_timer (__PRETTY_FUNCTION__,
Daniel Malead01b2952012-11-29 21:49:15 +0000276 "ObjectContainerBSDArchive::CreateInstance (module = %s/%s, file = %p, file_offset = 0x%8.8" PRIx64 ", file_size = 0x%8.8" PRIx64 ")",
Greg Claytone72dfb32012-02-24 01:59:29 +0000277 module_sp->GetFileSpec().GetDirectory().AsCString(),
278 module_sp->GetFileSpec().GetFilename().AsCString(),
Jason Molenda521d32d2012-09-11 06:35:15 +0000279 file, (uint64_t) offset, (uint64_t) length);
Greg Claytonaecb12b2012-01-09 23:59:30 +0000280
Greg Claytone72dfb32012-02-24 01:59:29 +0000281 Archive::shared_ptr archive_sp (Archive::FindCachedArchive (*file, module_sp->GetArchitecture(), module_sp->GetModificationTime()));
Greg Clayton44435ed2012-01-12 05:25:17 +0000282
Greg Claytone72dfb32012-02-24 01:59:29 +0000283 std::auto_ptr<ObjectContainerBSDArchive> container_ap(new ObjectContainerBSDArchive (module_sp, data_sp, file, offset, length));
Greg Clayton44435ed2012-01-12 05:25:17 +0000284
285 if (container_ap.get())
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000286 {
Greg Clayton44435ed2012-01-12 05:25:17 +0000287 if (archive_sp)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000288 {
Greg Clayton44435ed2012-01-12 05:25:17 +0000289 // We already have this archive in our cache, use it
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000290 container_ap->SetArchive (archive_sp);
291 return container_ap.release();
292 }
Greg Clayton44435ed2012-01-12 05:25:17 +0000293 else if (container_ap->ParseHeader())
294 return container_ap.release();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000295 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000296 }
297 return NULL;
298}
299
300
301
302bool
Greg Clayton44435ed2012-01-12 05:25:17 +0000303ObjectContainerBSDArchive::MagicBytesMatch (const DataExtractor &data)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000304{
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000305 uint32_t offset = 0;
306 const char* armag = (const char* )data.PeekData (offset, sizeof(ar_hdr));
307 if (armag && ::strncmp(armag, ARMAG, SARMAG) == 0)
308 {
309 armag += offsetof(struct ar_hdr, ar_fmag) + SARMAG;
310 if (strncmp(armag, ARFMAG, 2) == 0)
311 return true;
312 }
313 return false;
314}
315
316ObjectContainerBSDArchive::ObjectContainerBSDArchive
317(
Greg Claytone72dfb32012-02-24 01:59:29 +0000318 const lldb::ModuleSP &module_sp,
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000319 DataBufferSP& dataSP,
320 const lldb_private::FileSpec *file,
321 lldb::addr_t offset,
322 lldb::addr_t size
323) :
Greg Claytone72dfb32012-02-24 01:59:29 +0000324 ObjectContainer (module_sp, file, offset, size, dataSP),
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000325 m_archive_sp ()
326{
327}
328void
329ObjectContainerBSDArchive::SetArchive (Archive::shared_ptr &archive_sp)
330{
331 m_archive_sp = archive_sp;
332}
333
334
335
336ObjectContainerBSDArchive::~ObjectContainerBSDArchive()
337{
338}
339
340bool
341ObjectContainerBSDArchive::ParseHeader ()
342{
343 if (m_archive_sp.get() == NULL)
344 {
345 if (m_data.GetByteSize() > 0)
346 {
Greg Claytone72dfb32012-02-24 01:59:29 +0000347 ModuleSP module_sp (GetModule());
348 if (module_sp)
349 {
350 m_archive_sp = Archive::ParseAndCacheArchiveForFile (m_file,
351 module_sp->GetArchitecture(),
352 module_sp->GetModificationTime(),
353 m_data);
354 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000355 }
356 }
357 return m_archive_sp.get() != NULL;
358}
359
360void
361ObjectContainerBSDArchive::Dump (Stream *s) const
362{
Jason Molendafd54b362011-09-20 21:44:10 +0000363 s->Printf("%p: ", this);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000364 s->Indent();
365 const size_t num_archs = GetNumArchitectures();
366 const size_t num_objects = GetNumObjects();
Jason Molendafd54b362011-09-20 21:44:10 +0000367 s->Printf("ObjectContainerBSDArchive, num_archs = %lu, num_objects = %lu", num_archs, num_objects);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000368 uint32_t i;
369 ArchSpec arch;
370 s->IndentMore();
371 for (i=0; i<num_archs; i++)
372 {
373 s->Indent();
374 GetArchitectureAtIndex(i, arch);
Jason Molendafd54b362011-09-20 21:44:10 +0000375 s->Printf("arch[%u] = %s\n", i, arch.GetArchitectureName());
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000376 }
377 for (i=0; i<num_objects; i++)
378 {
379 s->Indent();
Jason Molendafd54b362011-09-20 21:44:10 +0000380 s->Printf("object[%u] = %s\n", i, GetObjectNameAtIndex (i));
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000381 }
382 s->IndentLess();
383 s->EOL();
384}
385
Greg Clayton762f7132011-09-18 18:59:15 +0000386ObjectFileSP
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000387ObjectContainerBSDArchive::GetObjectFile (const FileSpec *file)
388{
Greg Claytone72dfb32012-02-24 01:59:29 +0000389 ModuleSP module_sp (GetModule());
390 if (module_sp)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000391 {
Greg Claytone72dfb32012-02-24 01:59:29 +0000392 if (module_sp->GetObjectName() && m_archive_sp)
393 {
394 Object *object = m_archive_sp->FindObject (module_sp->GetObjectName());
395 if (object)
396 return ObjectFile::FindPlugin (module_sp,
397 file,
Greg Clayton824e7c02012-11-15 19:37:18 +0000398 m_offset + object->ar_file_offset,
Greg Claytone72dfb32012-02-24 01:59:29 +0000399 object->ar_file_size,
400 m_data.GetSharedDataBuffer());
401 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000402 }
Greg Clayton762f7132011-09-18 18:59:15 +0000403 return ObjectFileSP();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000404}
405
406
407//------------------------------------------------------------------
408// PluginInterface protocol
409//------------------------------------------------------------------
410const char *
411ObjectContainerBSDArchive::GetPluginName()
412{
413 return "object-container.bsd-archive";
414}
415
416const char *
417ObjectContainerBSDArchive::GetShortPluginName()
418{
419 return GetPluginNameStatic();
420}
421
422uint32_t
423ObjectContainerBSDArchive::GetPluginVersion()
424{
425 return 1;
426}
427