blob: d155b69beeca82f2f29fb87b91eb6a2f53f66000 [file] [log] [blame]
Chris Lattner23219d12003-09-22 23:42:00 +00001//===- ArchiveReader.cpp - Code to read LLVM bytecode from .a files -------===//
John Criswellb576c942003-10-20 19:43:21 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file was developed by the LLVM research group and is distributed under
6// the University of Illinois Open Source License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
Chris Lattner968cfd02003-04-19 21:45:34 +00009//
10// This file implements the ReadArchiveFile interface, which allows a linker to
11// read all of the LLVM bytecode files contained in a .a file. This file
12// understands the standard system .a file format. This can only handle the .a
Misha Brukman09ff1502003-04-23 02:59:05 +000013// variant prevalent on Linux systems so far, but may be extended. See
Chris Lattner968cfd02003-04-19 21:45:34 +000014// information in this source file for more information:
15// http://sources.redhat.com/cgi-bin/cvsweb.cgi/src/bfd/archive.c?cvsroot=src
16//
17//===----------------------------------------------------------------------===//
18
19#include "llvm/Bytecode/Reader.h"
20#include "llvm/Module.h"
John Criswell7a73b802003-06-30 21:59:07 +000021#include "Config/sys/stat.h"
22#include "Config/sys/mman.h"
23#include "Config/fcntl.h"
Chris Lattner968cfd02003-04-19 21:45:34 +000024
25namespace {
26 struct ar_hdr {
27 char name[16];
28 char date[12];
29 char uid[6];
30 char gid[6];
31 char mode[8];
32 char size[10];
33 char fmag[2]; // Always equal to '`\n'
34 };
35
36 enum ObjectType {
37 UserObject, // A user .o/.bc file
38 Unknown, // Unknown file, just ignore it
39 SVR4LongFilename, // a "//" section used for long file names
40 };
41}
42
43
44// getObjectType - Determine the type of object that this header represents.
45// This is capable of parsing the variety of special sections used for various
46// purposes.
47static enum ObjectType getObjectType(ar_hdr *H, unsigned Size) {
48 // Check for sections with special names...
49 if (!memcmp(H->name, "// ", 16))
50 return SVR4LongFilename;
51
52 // Check to see if it looks like an llvm object file...
53 if (Size >= 4 && !memcmp(H+1, "llvm", 4))
54 return UserObject;
55
56 return Unknown;
57}
58
59
60static inline bool Error(std::string *ErrorStr, const char *Message) {
61 if (ErrorStr) *ErrorStr = Message;
62 return true;
63}
64
65static bool ParseLongFilenameSection(unsigned char *Buffer, unsigned Size,
66 std::vector<std::string> &LongFilenames,
67 std::string *S) {
68 if (!LongFilenames.empty())
69 return Error(S, "archive file contains multiple long filename entries");
70
71 while (Size) {
72 // Long filename entries are newline delimited to keep the archive readable.
73 unsigned char *Ptr = (unsigned char*)memchr(Buffer, '\n', Size);
74 if (Ptr == 0)
75 return Error(S, "archive long filename entry doesn't end with newline!");
76 assert(*Ptr == '\n');
77
78 if (Ptr == Buffer) break; // Last entry contains just a newline.
79
80 unsigned char *End = Ptr;
81 if (End[-1] == '/') --End; // Remove trailing / from name
82
83 LongFilenames.push_back(std::string(Buffer, End));
84 Size -= Ptr-Buffer+1;
85 Buffer = Ptr+1;
86 }
87
88 return false;
89}
90
91
Chris Lattner75f20532003-04-22 18:02:52 +000092static bool ReadArchiveBuffer(const std::string &Filename,
93 unsigned char *Buffer, unsigned Length,
Chris Lattner968cfd02003-04-19 21:45:34 +000094 std::vector<Module*> &Objects,
95 std::string *ErrorStr) {
96 if (Length < 8 || memcmp(Buffer, "!<arch>\n", 8))
97 return Error(ErrorStr, "signature incorrect for an archive file!");
98 Buffer += 8; Length -= 8; // Skip the magic string.
99
100 std::vector<std::string> LongFilenames;
101
102 while (Length >= sizeof(ar_hdr)) {
103 ar_hdr *Hdr = (ar_hdr*)Buffer;
104 unsigned Size = atoi(Hdr->size);
105 if (Size+sizeof(ar_hdr) > Length)
106 return Error(ErrorStr, "invalid record length in archive file!");
107
108 switch (getObjectType(Hdr, Size)) {
109 case SVR4LongFilename:
110 // If this is a long filename section, read all of the file names into the
111 // LongFilenames vector.
112 //
113 if (ParseLongFilenameSection(Buffer+sizeof(ar_hdr), Size,
114 LongFilenames, ErrorStr))
115 return true;
116 break;
117 case UserObject: {
Chris Lattner75f20532003-04-22 18:02:52 +0000118 Module *M = ParseBytecodeBuffer(Buffer+sizeof(ar_hdr), Size,
119 Filename+":somefile", ErrorStr);
Chris Lattner968cfd02003-04-19 21:45:34 +0000120 if (!M) return true;
121 Objects.push_back(M);
122 break;
123 }
124 case Unknown:
125 std::cerr << "ReadArchiveBuffer: WARNING: Skipping unknown file: ";
126 std::cerr << std::string(Hdr->name, Hdr->name+sizeof(Hdr->name+1)) <<"\n";
127 break; // Just ignore unknown files.
128 }
129
130 // Round Size up to an even number...
131 Size = (Size+1)/2*2;
132 Buffer += sizeof(ar_hdr)+Size; // Move to the next entry
133 Length -= sizeof(ar_hdr)+Size;
134 }
135
136 return Length != 0;
137}
138
139
Misha Brukman37f92e22003-09-11 22:34:13 +0000140// ReadArchiveFile - Read bytecode files from the specified .a file, returning
Chris Lattner968cfd02003-04-19 21:45:34 +0000141// true on error, or false on success. This does not support reading files from
142// standard input.
143//
144bool ReadArchiveFile(const std::string &Filename, std::vector<Module*> &Objects,
145 std::string *ErrorStr) {
146 int FD = open(Filename.c_str(), O_RDONLY);
147 if (FD == -1)
148 return Error(ErrorStr, "Error opening file!");
149
150 // Stat the file to get its length...
151 struct stat StatBuf;
152 if (fstat(FD, &StatBuf) == -1 || StatBuf.st_size == 0)
153 return Error(ErrorStr, "Error stat'ing file!");
154
155 // mmap in the file all at once...
156 int Length = StatBuf.st_size;
157 unsigned char *Buffer = (unsigned char*)mmap(0, Length, PROT_READ,
158 MAP_PRIVATE, FD, 0);
159 if (Buffer == (unsigned char*)MAP_FAILED)
160 return Error(ErrorStr, "Error mmapping file!");
161
162 // Parse the archive files we mmap'ped in
Chris Lattner75f20532003-04-22 18:02:52 +0000163 bool Result = ReadArchiveBuffer(Filename, Buffer, Length, Objects, ErrorStr);
Chris Lattner968cfd02003-04-19 21:45:34 +0000164
165 // Unmmap the archive...
166 munmap((char*)Buffer, Length);
167
168 if (Result) // Free any loaded objects
169 while (!Objects.empty()) {
170 delete Objects.back();
171 Objects.pop_back();
172 }
173
174 return Result;
175}