1 //===------ utils/archive2yaml.cpp - obj2yaml conversion tool ---*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
10 #include "llvm/BinaryFormat/Magic.h"
11 #include "llvm/ObjectYAML/ArchiveYAML.h"
19 Expected
<ArchYAML::Archive
*> dump(MemoryBufferRef Source
) {
20 StringRef Buffer
= Source
.getBuffer();
21 assert(file_magic::archive
== identify_magic(Buffer
));
23 std::unique_ptr
<ArchYAML::Archive
> Obj
=
24 std::make_unique
<ArchYAML::Archive
>();
26 StringRef Magic
= "!<arch>\n";
27 if (!Buffer
.startswith(Magic
))
28 return createStringError(std::errc::not_supported
,
29 "only regular archives are supported");
31 Buffer
= Buffer
.drop_front(Magic
.size());
33 Obj
->Members
.emplace();
34 while (!Buffer
.empty()) {
35 uint64_t Offset
= Buffer
.data() - Source
.getBuffer().data();
36 if (Buffer
.size() < sizeof(ArchiveHeader
))
37 return createStringError(
38 std::errc::illegal_byte_sequence
,
39 "unable to read the header of a child at offset 0x%" PRIx64
,
42 const ArchiveHeader
&Hdr
=
43 *reinterpret_cast<const ArchiveHeader
*>(Buffer
.data());
44 Buffer
= Buffer
.drop_front(sizeof(ArchiveHeader
));
46 auto ToString
= [](ArrayRef
<char> V
) {
47 // We don't want to dump excessive spaces.
48 return StringRef(V
.data(), V
.size()).rtrim(' ');
51 ArchYAML::Archive::Child C
;
52 C
.Fields
["Name"].Value
= ToString(Hdr
.Name
);
53 C
.Fields
["LastModified"].Value
= ToString(Hdr
.LastModified
);
54 C
.Fields
["UID"].Value
= ToString(Hdr
.UID
);
55 C
.Fields
["GID"].Value
= ToString(Hdr
.GID
);
56 C
.Fields
["AccessMode"].Value
= ToString(Hdr
.AccessMode
);
57 StringRef SizeStr
= ToString(Hdr
.Size
);
58 C
.Fields
["Size"].Value
= SizeStr
;
59 C
.Fields
["Terminator"].Value
= ToString(Hdr
.Terminator
);
62 if (SizeStr
.getAsInteger(10, Size
))
63 return createStringError(
64 std::errc::illegal_byte_sequence
,
65 "unable to read the size of a child at offset 0x%" PRIx64
66 " as integer: \"%s\"",
67 Offset
, SizeStr
.str().c_str());
68 if (Buffer
.size() < Size
)
69 return createStringError(
70 std::errc::illegal_byte_sequence
,
71 "unable to read the data of a child at offset 0x%" PRIx64
72 " of size %" PRId64
": the remaining archive size is %zu",
73 Offset
, Size
, Buffer
.size());
75 C
.Content
= arrayRefFromStringRef(Buffer
.take_front(Size
));
77 const bool HasPaddingByte
= (Size
& 1) && Buffer
.size() > Size
;
79 C
.PaddingByte
= Buffer
[Size
];
81 Obj
->Members
->push_back(C
);
82 // If the size is odd, consume a padding byte.
83 Buffer
= Buffer
.drop_front(HasPaddingByte
? Size
+ 1 : Size
);
90 struct ArchiveHeader
{
92 char LastModified
[12];
103 Error
archive2yaml(raw_ostream
&Out
, MemoryBufferRef Source
) {
104 ArchiveDumper Dumper
;
105 Expected
<ArchYAML::Archive
*> YAMLOrErr
= Dumper
.dump(Source
);
107 return YAMLOrErr
.takeError();
109 std::unique_ptr
<ArchYAML::Archive
> YAML(YAMLOrErr
.get());
110 yaml::Output
Yout(Out
);
113 return Error::success();