blob: c2fb2a552b3c240740990f46f78835bb604204b9 [file] [log] [blame]
Chris Lattner24943d22010-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"
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