1//===----------------------------------------------------------------------===//
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 "PseudoProbeLinker.h"
10#include "LinkUtils.h"
11#include "llvm/ADT/SmallString.h"
12#include "llvm/ADT/StringSwitch.h"
13#include "llvm/ADT/Twine.h"
14#include "llvm/Object/MachO.h"
15#include "llvm/Support/FileSystem.h"
16#include "llvm/Support/Path.h"
17#include "llvm/Support/raw_ostream.h"
18#include "llvm/TargetParser/Triple.h"
19#include <cassert>
20
21namespace llvm {
22namespace dsymutil {
23
24Error PseudoProbeLinker::collect(const object::ObjectFile &Obj) {
25 const auto *MO = dyn_cast<object::MachOObjectFile>(Val: &Obj);
26 if (!MO)
27 return Error::success();
28
29 for (const object::SectionRef &Section : MO->sections()) {
30 Expected<StringRef> NameOrErr = Section.getName();
31 if (!NameOrErr)
32 return NameOrErr.takeError();
33
34 std::string *Dest = StringSwitch<std::string *>(*NameOrErr)
35 .Case(S: "__probes", Value: &Probes)
36 .Case(S: "__probe_descs", Value: &ProbeDescs)
37 .Default(Value: nullptr);
38 if (!Dest)
39 continue;
40
41 assert(Section.relocations().empty() &&
42 "pseudo-probe section unexpectedly carries relocations");
43 if (!Section.relocations().empty())
44 return createStringError(
45 EC: inconvertibleErrorCode(),
46 S: "unexpected relocations in pseudo-probe section " + *NameOrErr);
47
48 Expected<StringRef> ContentsOrErr = Section.getContents();
49 if (!ContentsOrErr)
50 return ContentsOrErr.takeError();
51 *Dest += *ContentsOrErr;
52 }
53 return Error::success();
54}
55
56Error PseudoProbeLinker::emit(const Triple &TheTriple) const {
57 if (empty())
58 return Error::success();
59
60 if (!Options.ResourceDir || Options.NoOutput)
61 return Error::success();
62
63 SmallString<128> Path;
64 sys::path::append(path&: Path, a: *Options.ResourceDir, b: "Profiling");
65 if (std::error_code EC = sys::fs::create_directories(path: Path.str(), IgnoreExisting: true,
66 Perms: sys::fs::perms::all_all))
67 return errorCodeToError(EC);
68
69 std::string Suffix;
70 if (Options.NumDebugMaps > 1)
71 Suffix = ("-" + TheTriple.getArchName()).str();
72
73 // Write pseudo_probes metadata.
74 Path.clear();
75 sys::path::append(path&: Path, a: *Options.ResourceDir, b: "Profiling",
76 c: "pseudo_probes" + Suffix);
77 std::error_code EC;
78 raw_fd_ostream ProbesOS(Path.str(), EC, sys::fs::OF_None);
79 if (EC)
80 return errorCodeToError(EC);
81 ProbesOS << getProbes();
82
83 // Write pseudo_probe_descs metadata.
84 Path.clear();
85 sys::path::append(path&: Path, a: *Options.ResourceDir, b: "Profiling",
86 c: "pseudo_probe_descs" + Suffix);
87 raw_fd_ostream DescsOS(Path.str(), EC, sys::fs::OF_None);
88 if (EC)
89 return errorCodeToError(EC);
90 DescsOS << getProbeDescs();
91
92 return Error::success();
93}
94
95} // end namespace dsymutil
96} // end namespace llvm
97