1//===- MultiArchSharedLibrary.cpp -----------------------------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
9#include "JSONFormatImpl.h"
10
11#include "clang/ScalableStaticAnalysis/Core/EntityLinker/LUSummaryEncoding.h"
12#include "clang/ScalableStaticAnalysis/Core/EntityLinker/MultiArchSharedLibrary.h"
13#include "llvm/TargetParser/Triple.h"
14
15namespace clang::ssaf {
16
17//----------------------------------------------------------------------------
18// MultiArchSharedLibrary
19//----------------------------------------------------------------------------
20
21llvm::Expected<MultiArchSharedLibrary>
22JSONFormat::readMultiArchSharedLibrary(llvm::StringRef Path) {
23 auto ExpectedJSON = readJSON(Path);
24 if (!ExpectedJSON) {
25 return ErrorBuilder::wrap(E: ExpectedJSON.takeError())
26 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "MultiArchSharedLibrary", ArgVals&: Path)
27 .build();
28 }
29
30 Object *RootObjectPtr = ExpectedJSON->getAsObject();
31 if (!RootObjectPtr) {
32 return ErrorBuilder::create(EC: std::errc::invalid_argument,
33 Fmt: ErrorMessages::FailedToReadObject,
34 ArgVals: "MultiArchSharedLibrary", ArgVals: "object")
35 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "MultiArchSharedLibrary", ArgVals&: Path)
36 .build();
37 }
38
39 if (auto Err = checkSummaryType(RootObject: *RootObjectPtr,
40 ExpectedType: JSONTypeValueMultiArchSharedLibrary)) {
41 return ErrorBuilder::wrap(E: std::move(Err))
42 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "MultiArchSharedLibrary", ArgVals&: Path)
43 .build();
44 }
45
46 auto ExpectedM = readMultiArchSharedLibraryFromObject(Root: *RootObjectPtr);
47 if (!ExpectedM) {
48 return ErrorBuilder::wrap(E: ExpectedM.takeError())
49 .context(Fmt: ErrorMessages::ReadingFromFile, ArgVals: "MultiArchSharedLibrary", ArgVals&: Path)
50 .build();
51 }
52
53 return std::move(*ExpectedM);
54}
55
56llvm::Expected<MultiArchSharedLibrary>
57JSONFormat::readMultiArchSharedLibraryFromObject(const Object &RootObject) {
58 const Array *NamespaceArray = RootObject.getArray(K: "namespace");
59 if (!NamespaceArray) {
60 return ErrorBuilder::create(EC: std::errc::invalid_argument,
61 Fmt: ErrorMessages::FailedToReadObjectAtField,
62 ArgVals: "NestedBuildNamespace", ArgVals: "namespace", ArgVals: "array")
63 .build();
64 }
65
66 auto ExpectedNamespace = nestedBuildNamespaceFromJSON(NestedBuildNamespaceArray: *NamespaceArray);
67 if (!ExpectedNamespace) {
68 return ErrorBuilder::wrap(E: ExpectedNamespace.takeError())
69 .context(Fmt: ErrorMessages::ReadingFromField, ArgVals: "NestedBuildNamespace",
70 ArgVals: "namespace")
71 .build();
72 }
73
74 const Array *MembersArray = RootObject.getArray(K: "members");
75 if (!MembersArray) {
76 return ErrorBuilder::create(EC: std::errc::invalid_argument,
77 Fmt: ErrorMessages::FailedToReadObjectAtField,
78 ArgVals: "MultiArchSharedLibrary members", ArgVals: "members",
79 ArgVals: "array")
80 .build();
81 }
82
83 MultiArchSharedLibrary M(std::move(*ExpectedNamespace));
84 auto &Members = getMembers(X&: M);
85 const auto &WrapperNamespace = getNamespace(X&: M);
86
87 for (const auto &[Index, MemberValue] : llvm::enumerate(First: *MembersArray)) {
88 const Object *MemberObject = MemberValue.getAsObject();
89 if (!MemberObject) {
90 return ErrorBuilder::create(EC: std::errc::invalid_argument,
91 Fmt: ErrorMessages::FailedToReadObjectAtIndex,
92 ArgVals: "MultiArchSharedLibrary member", ArgVals&: Index,
93 ArgVals: "object")
94 .build();
95 }
96
97 if (auto Err = checkSummaryType(RootObject: *MemberObject, ExpectedType: JSONTypeValueLUSummary)) {
98 return ErrorBuilder::wrap(E: std::move(Err))
99 .context(Fmt: ErrorMessages::ReadingFromIndex,
100 ArgVals: "MultiArchSharedLibrary member", ArgVals&: Index)
101 .build();
102 }
103
104 auto ExpectedMember = readLUSummaryEncodingFromObject(Root: *MemberObject);
105 if (!ExpectedMember) {
106 return ErrorBuilder::wrap(E: ExpectedMember.takeError())
107 .context(Fmt: ErrorMessages::ReadingFromIndex,
108 ArgVals: "MultiArchSharedLibrary member", ArgVals&: Index)
109 .build();
110 }
111
112 // Every per-arch slice must resolve to the same shared-library identity,
113 // so the member's LUNamespace must equal the wrapper's Namespace.
114 if (WrapperNamespace != getLUNamespace(X&: *ExpectedMember)) {
115 return ErrorBuilder::create(EC: std::errc::invalid_argument,
116 Fmt: ErrorMessages::MismatchedNestedNamespace,
117 ArgVals: "lu_namespace")
118 .context(Fmt: ErrorMessages::ReadingFromIndex,
119 ArgVals: "MultiArchSharedLibrary member", ArgVals&: Index)
120 .build();
121 }
122
123 auto [It, Inserted] = Members.insert(
124 x: std::make_unique<LUSummaryEncoding>(args: std::move(*ExpectedMember)));
125 if (!Inserted) {
126 auto MemberTriple = llvm::Triple::normalize(Str: getTargetTriple(X&: **It).str());
127 return ErrorBuilder::create(EC: std::errc::invalid_argument,
128 Fmt: ErrorMessages::FailedInsertionOnDuplication,
129 ArgVals: "MultiArchSharedLibrary member", ArgVals&: Index,
130 ArgVals&: MemberTriple)
131 .build();
132 }
133 }
134
135 return std::move(M);
136}
137
138llvm::Error
139JSONFormat::writeMultiArchSharedLibrary(const MultiArchSharedLibrary &M,
140 llvm::StringRef Path) {
141 Object RootObject;
142
143 RootObject[JSONTypeKey] = JSONTypeValueMultiArchSharedLibrary;
144
145 RootObject["namespace"] = nestedBuildNamespaceToJSON(NBN: getNamespace(X: M));
146
147 Array MembersArray;
148 MembersArray.reserve(S: getMembers(X: M).size());
149 for (const auto &Member : getMembers(X: M)) {
150 MembersArray.push_back(E: luSummaryEncodingToJSON(E: *Member));
151 }
152 RootObject["members"] = std::move(MembersArray);
153
154 if (auto Error = writeJSON(V: std::move(RootObject), Path)) {
155 return ErrorBuilder::wrap(E: std::move(Error))
156 .context(Fmt: ErrorMessages::WritingToFile, ArgVals: "MultiArchSharedLibrary", ArgVals&: Path)
157 .build();
158 }
159
160 return llvm::Error::success();
161}
162
163} // namespace clang::ssaf
164