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