mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 10:42:39 +01:00
[llvm-objcopy] Delete --build-id-link-{dir,input,output}
The few options are niche. They solved a problem which was traditionally solved with more shell commands (`llvm-readelf -n` fetches the Build ID. Then `ln` is used to hard link the file to a directory derived from the Build ID.) Due to limitation, they are no longer used by Fuchsia and they don't appear to be used elsewhere (checked with Google Search and Debian Code Search). So delete them without a transition period. Announcement: https://lists.llvm.org/pipermail/llvm-dev/2021-February/148446.html Differential Revision: https://reviews.llvm.org/D96310
This commit is contained in:
parent
1172c76018
commit
3296757d5e
@ -285,23 +285,6 @@ them.
|
||||
Allow :program:`llvm-objcopy` to remove sections even if it would leave invalid
|
||||
section references. Any invalid sh_link fields will be set to zero.
|
||||
|
||||
.. option:: --build-id-link-dir <dir>
|
||||
|
||||
Set the directory used by :option:`--build-id-link-input` and
|
||||
:option:`--build-id-link-output`.
|
||||
|
||||
.. option:: --build-id-link-input <suffix>
|
||||
|
||||
Hard-link the input to ``<dir>/xx/xxx<suffix>``, where ``<dir>`` is the directory
|
||||
specified by :option:`--build-id-link-dir`. The path used is derived from the
|
||||
hex build ID.
|
||||
|
||||
.. option:: --build-id-link-output <suffix>
|
||||
|
||||
Hard-link the output to ``<dir>/xx/xxx<suffix>``, where ``<dir>`` is the directory
|
||||
specified by :option:`--build-id-link-dir`. The path used is derived from the
|
||||
hex build ID.
|
||||
|
||||
.. option:: --change-start <incr>, --adjust-start
|
||||
|
||||
Add ``<incr>`` to the program's start address. Can be specified multiple
|
||||
|
@ -124,6 +124,9 @@ During this release ...
|
||||
Changes to the LLVM tools
|
||||
---------------------------------
|
||||
|
||||
* The options ``--build-id-link-{dir,input,output}`` have been deleted.
|
||||
(`D96310 <https://reviews.llvm.org/D96310>`_)
|
||||
|
||||
Changes to LLDB
|
||||
---------------------------------
|
||||
|
||||
|
@ -1,21 +0,0 @@
|
||||
# RUN: yaml2obj %s -o %t
|
||||
# RUN: not llvm-objcopy --build-id-link-dir=%t-dir --build-id-link-input=.debug %t 2>&1 >/dev/null | FileCheck %s
|
||||
|
||||
# CHECK: build ID is smaller than two bytes
|
||||
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_EXEC
|
||||
Machine: EM_X86_64
|
||||
Sections:
|
||||
- Name: .note.gnu.build-id
|
||||
Type: SHT_NOTE
|
||||
Flags: [ SHF_ALLOC ]
|
||||
Content: 040000000100000003000000474E55004F000000
|
||||
ProgramHeaders:
|
||||
- Type: PT_NOTE
|
||||
Flags: [ PF_R ]
|
||||
FirstSec: .note.gnu.build-id
|
||||
LastSec: .note.gnu.build-id
|
@ -1,56 +0,0 @@
|
||||
# RUN: yaml2obj %s -o %t
|
||||
# RUN: rm -fr %t-dir && mkdir %t-dir
|
||||
|
||||
# RUN: llvm-objcopy --build-id-link-dir=%t-dir %t %t2
|
||||
# RUN: not test -e %t-dir/4f/cb712aa6387724a9f465a32cd8c14b
|
||||
|
||||
# RUN: llvm-objcopy --build-id-link-dir=%t-dir --build-id-link-input=.debug %t %t3
|
||||
# RUN: cmp %t-dir/4f/cb712aa6387724a9f465a32cd8c14b.debug %t
|
||||
# RUN: rm %t-dir/4f/cb712aa6387724a9f465a32cd8c14b.debug
|
||||
|
||||
# RUN: llvm-objcopy --build-id-link-dir=%t-dir --build-id-link-output "" --strip-sections %t %t4
|
||||
# RUN: cmp %t-dir/4f/cb712aa6387724a9f465a32cd8c14b %t4
|
||||
# RUN: rm %t-dir/4f/cb712aa6387724a9f465a32cd8c14b
|
||||
|
||||
# Linking the output of an inplace argument means that the file in the build-id
|
||||
# directory will be hard-linked to the resulting file.
|
||||
# RUN: cp %t %t5
|
||||
# RUN: llvm-objcopy --build-id-link-dir=%t-dir --build-id-link-output "" --strip-sections %t5
|
||||
# RUN: cmp %t-dir/4f/cb712aa6387724a9f465a32cd8c14b %t5
|
||||
# RUN: rm %t-dir/4f/cb712aa6387724a9f465a32cd8c14b
|
||||
|
||||
# Linking the input of an inplace argument means that the file in the build-id
|
||||
# directory will be hard-linked to the original file.
|
||||
# RUN: cp %t %t6
|
||||
# RUN: llvm-objcopy --build-id-link-dir=%t-dir --build-id-link-input=.debug --strip-sections %t6
|
||||
# RUN: cmp %t-dir/4f/cb712aa6387724a9f465a32cd8c14b.debug %t
|
||||
# RUN: rm %t-dir/4f/cb712aa6387724a9f465a32cd8c14b.debug
|
||||
|
||||
# You can use both at once.
|
||||
# RUN: llvm-objcopy --build-id-link-dir=%t-dir --build-id-link-output "" --build-id-link-input=.debug --strip-sections %t %t7
|
||||
# RUN: cmp %t-dir/4f/cb712aa6387724a9f465a32cd8c14b.debug %t
|
||||
# RUN: cmp %t-dir/4f/cb712aa6387724a9f465a32cd8c14b %t7
|
||||
# RUN: rm %t-dir/4f/cb712aa6387724a9f465a32cd8c14b.debug
|
||||
# RUN: rm %t-dir/4f/cb712aa6387724a9f465a32cd8c14b
|
||||
|
||||
# --build-id-link-output can have a suffix as well
|
||||
# RUN: llvm-objcopy --build-id-link-dir=%t-dir --build-id-link-output=.debug --only-keep-debug %t %t8
|
||||
# RUN: cmp %t-dir/4f/cb712aa6387724a9f465a32cd8c14b.debug %t8
|
||||
# RUN: rm %t-dir/4f/cb712aa6387724a9f465a32cd8c14b.debug
|
||||
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_EXEC
|
||||
Machine: EM_X86_64
|
||||
Sections:
|
||||
- Name: .note.gnu.build-id
|
||||
Type: SHT_NOTE
|
||||
Flags: [ SHF_ALLOC ]
|
||||
Content: 040000001000000003000000474E55004FCB712AA6387724A9F465A32CD8C14B
|
||||
ProgramHeaders:
|
||||
- Type: PT_NOTE
|
||||
Flags: [ PF_R ]
|
||||
FirstSec: .note.gnu.build-id
|
||||
LastSec: .note.gnu.build-id
|
@ -1,11 +0,0 @@
|
||||
# RUN: yaml2obj %s -o %t
|
||||
# RUN: not llvm-objcopy --build-id-link-dir=%t-dir --build-id-link-input=.debug %t 2>&1 >/dev/null | FileCheck %s
|
||||
|
||||
# CHECK: could not find build ID
|
||||
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_EXEC
|
||||
Machine: EM_X86_64
|
@ -1,21 +0,0 @@
|
||||
# RUN: yaml2obj %s -o %t
|
||||
# RUN: not llvm-objcopy --build-id-link-dir=%t-dir --build-id-link-input=.debug %t 2>&1 >/dev/null | FileCheck %s -DINPUT=%t
|
||||
|
||||
# CHECK: error: '[[INPUT]]': could not find build ID
|
||||
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_EXEC
|
||||
Machine: EM_X86_64
|
||||
Sections:
|
||||
- Name: .note.foo
|
||||
Type: SHT_NOTE
|
||||
Flags: [ SHF_ALLOC ]
|
||||
Content: 000000000000000000000000
|
||||
ProgramHeaders:
|
||||
- Type: PT_NOTE
|
||||
Flags: [ PF_R ]
|
||||
FirstSec: .note.foo
|
||||
LastSec: .note.foo
|
@ -249,17 +249,15 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj) {
|
||||
if (Error E = addGnuDebugLink(Obj, Config.AddGnuDebugLink))
|
||||
return E;
|
||||
|
||||
if (Config.AllowBrokenLinks || !Config.BuildIdLinkDir.empty() ||
|
||||
Config.BuildIdLinkInput || Config.BuildIdLinkOutput ||
|
||||
!Config.SplitDWO.empty() || !Config.SymbolsPrefix.empty() ||
|
||||
!Config.AllocSectionsPrefix.empty() || !Config.DumpSection.empty() ||
|
||||
!Config.KeepSection.empty() || Config.NewSymbolVisibility ||
|
||||
!Config.SymbolsToGlobalize.empty() || !Config.SymbolsToKeep.empty() ||
|
||||
!Config.SymbolsToLocalize.empty() || !Config.SymbolsToWeaken.empty() ||
|
||||
!Config.SymbolsToKeepGlobal.empty() || !Config.SectionsToRename.empty() ||
|
||||
!Config.SetSectionAlignment.empty() || Config.ExtractDWO ||
|
||||
Config.LocalizeHidden || Config.PreserveDates || Config.StripDWO ||
|
||||
Config.StripNonAlloc || Config.StripSections ||
|
||||
if (Config.AllowBrokenLinks || !Config.SplitDWO.empty() ||
|
||||
!Config.SymbolsPrefix.empty() || !Config.AllocSectionsPrefix.empty() ||
|
||||
!Config.DumpSection.empty() || !Config.KeepSection.empty() ||
|
||||
Config.NewSymbolVisibility || !Config.SymbolsToGlobalize.empty() ||
|
||||
!Config.SymbolsToKeep.empty() || !Config.SymbolsToLocalize.empty() ||
|
||||
!Config.SymbolsToWeaken.empty() || !Config.SymbolsToKeepGlobal.empty() ||
|
||||
!Config.SectionsToRename.empty() || !Config.SetSectionAlignment.empty() ||
|
||||
Config.ExtractDWO || Config.LocalizeHidden || Config.PreserveDates ||
|
||||
Config.StripDWO || Config.StripNonAlloc || Config.StripSections ||
|
||||
Config.StripSwiftSymbols || Config.Weaken ||
|
||||
Config.DecompressDebugSections ||
|
||||
Config.DiscardMode == DiscardType::Locals ||
|
||||
|
@ -607,13 +607,6 @@ parseObjcopyOptions(ArrayRef<const char *> ArgsArr,
|
||||
Config.GnuDebugLinkCRC32 =
|
||||
llvm::crc32(arrayRefFromStringRef(Debug->getBuffer()));
|
||||
}
|
||||
Config.BuildIdLinkDir = InputArgs.getLastArgValue(OBJCOPY_build_id_link_dir);
|
||||
if (InputArgs.hasArg(OBJCOPY_build_id_link_input))
|
||||
Config.BuildIdLinkInput =
|
||||
InputArgs.getLastArgValue(OBJCOPY_build_id_link_input);
|
||||
if (InputArgs.hasArg(OBJCOPY_build_id_link_output))
|
||||
Config.BuildIdLinkOutput =
|
||||
InputArgs.getLastArgValue(OBJCOPY_build_id_link_output);
|
||||
Config.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo);
|
||||
Config.SymbolsPrefix = InputArgs.getLastArgValue(OBJCOPY_prefix_symbols);
|
||||
Config.AllocSectionsPrefix =
|
||||
|
@ -163,9 +163,6 @@ struct CopyConfig {
|
||||
StringRef AddGnuDebugLink;
|
||||
// Cached gnu_debuglink's target CRC
|
||||
uint32_t GnuDebugLinkCRC32;
|
||||
StringRef BuildIdLinkDir;
|
||||
Optional<StringRef> BuildIdLinkInput;
|
||||
Optional<StringRef> BuildIdLinkOutput;
|
||||
Optional<StringRef> ExtractPartition;
|
||||
StringRef SplitDWO;
|
||||
StringRef SymbolsPrefix;
|
||||
|
@ -166,43 +166,6 @@ static std::unique_ptr<Writer> createWriter(const CopyConfig &Config,
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
static Expected<ArrayRef<uint8_t>>
|
||||
findBuildID(const CopyConfig &Config, const object::ELFFile<ELFT> &In) {
|
||||
auto PhdrsOrErr = In.program_headers();
|
||||
if (auto Err = PhdrsOrErr.takeError())
|
||||
return createFileError(Config.InputFilename, std::move(Err));
|
||||
|
||||
for (const auto &Phdr : *PhdrsOrErr) {
|
||||
if (Phdr.p_type != PT_NOTE)
|
||||
continue;
|
||||
Error Err = Error::success();
|
||||
for (auto Note : In.notes(Phdr, Err))
|
||||
if (Note.getType() == NT_GNU_BUILD_ID && Note.getName() == ELF_NOTE_GNU)
|
||||
return Note.getDesc();
|
||||
if (Err)
|
||||
return createFileError(Config.InputFilename, std::move(Err));
|
||||
}
|
||||
|
||||
return createFileError(Config.InputFilename,
|
||||
createStringError(llvm::errc::invalid_argument,
|
||||
"could not find build ID"));
|
||||
}
|
||||
|
||||
static Expected<ArrayRef<uint8_t>>
|
||||
findBuildID(const CopyConfig &Config, const object::ELFObjectFileBase &In) {
|
||||
if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(&In))
|
||||
return findBuildID(Config, O->getELFFile());
|
||||
else if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(&In))
|
||||
return findBuildID(Config, O->getELFFile());
|
||||
else if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(&In))
|
||||
return findBuildID(Config, O->getELFFile());
|
||||
else if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(&In))
|
||||
return findBuildID(Config, O->getELFFile());
|
||||
|
||||
llvm_unreachable("Bad file format");
|
||||
}
|
||||
|
||||
template <class... Ts>
|
||||
static Error makeStringError(std::error_code EC, const Twine &Msg,
|
||||
Ts &&... Args) {
|
||||
@ -210,59 +173,6 @@ static Error makeStringError(std::error_code EC, const Twine &Msg,
|
||||
return createStringError(EC, FullMsg.c_str(), std::forward<Ts>(Args)...);
|
||||
}
|
||||
|
||||
#define MODEL_8 "%%%%%%%%"
|
||||
#define MODEL_16 MODEL_8 MODEL_8
|
||||
#define MODEL_32 (MODEL_16 MODEL_16)
|
||||
|
||||
static Error linkToBuildIdDir(const CopyConfig &Config, StringRef ToLink,
|
||||
StringRef Suffix,
|
||||
ArrayRef<uint8_t> BuildIdBytes) {
|
||||
SmallString<128> Path = Config.BuildIdLinkDir;
|
||||
sys::path::append(Path, llvm::toHex(BuildIdBytes[0], /*LowerCase*/ true));
|
||||
if (auto EC = sys::fs::create_directories(Path))
|
||||
return createFileError(
|
||||
Path.str(),
|
||||
makeStringError(EC, "cannot create build ID link directory"));
|
||||
|
||||
sys::path::append(Path,
|
||||
llvm::toHex(BuildIdBytes.slice(1), /*LowerCase*/ true));
|
||||
Path += Suffix;
|
||||
SmallString<128> TmpPath;
|
||||
// create_hard_link races so we need to link to a temporary path but
|
||||
// we want to make sure that we choose a filename that does not exist.
|
||||
// By using 32 model characters we get 128-bits of entropy. It is
|
||||
// unlikely that this string has ever existed before much less exists
|
||||
// on this disk or in the current working directory.
|
||||
// Additionally we prepend the original Path for debugging but also
|
||||
// because it ensures that we're linking within a directory on the same
|
||||
// partition on the same device which is critical. It has the added
|
||||
// win of yet further decreasing the odds of a conflict.
|
||||
sys::fs::createUniquePath(Twine(Path) + "-" + MODEL_32 + ".tmp", TmpPath,
|
||||
/*MakeAbsolute*/ false);
|
||||
if (auto EC = sys::fs::create_hard_link(ToLink, TmpPath)) {
|
||||
Path.push_back('\0');
|
||||
return makeStringError(EC, "cannot link '%s' to '%s'", ToLink.data(),
|
||||
Path.data());
|
||||
}
|
||||
// We then atomically rename the link into place which will just move the
|
||||
// link. If rename fails something is more seriously wrong so just return
|
||||
// an error.
|
||||
if (auto EC = sys::fs::rename(TmpPath, Path)) {
|
||||
Path.push_back('\0');
|
||||
return makeStringError(EC, "cannot link '%s' to '%s'", ToLink.data(),
|
||||
Path.data());
|
||||
}
|
||||
// If `Path` was already a hard-link to the same underlying file then the
|
||||
// temp file will be left so we need to remove it. Remove will not cause
|
||||
// an error by default if the file is already gone so just blindly remove
|
||||
// it rather than checking.
|
||||
if (auto EC = sys::fs::remove(TmpPath)) {
|
||||
TmpPath.push_back('\0');
|
||||
return makeStringError(EC, "could not remove '%s'", TmpPath.data());
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
static Error splitDWOToFile(const CopyConfig &Config, const Reader &Reader,
|
||||
StringRef File, ElfType OutputElfType) {
|
||||
Expected<std::unique_ptr<Object>> DWOFile = Reader.create(false);
|
||||
@ -828,37 +738,12 @@ Error executeObjcopyOnBinary(const CopyConfig &Config,
|
||||
const ElfType OutputElfType =
|
||||
Config.OutputArch ? getOutputElfType(Config.OutputArch.getValue())
|
||||
: getOutputElfType(In);
|
||||
ArrayRef<uint8_t> BuildIdBytes;
|
||||
|
||||
if (!Config.BuildIdLinkDir.empty()) {
|
||||
auto BuildIdBytesOrErr = findBuildID(Config, In);
|
||||
if (auto E = BuildIdBytesOrErr.takeError())
|
||||
return E;
|
||||
BuildIdBytes = *BuildIdBytesOrErr;
|
||||
|
||||
if (BuildIdBytes.size() < 2)
|
||||
return createFileError(
|
||||
Config.InputFilename,
|
||||
createStringError(object_error::parse_failed,
|
||||
"build ID is smaller than two bytes"));
|
||||
}
|
||||
|
||||
if (!Config.BuildIdLinkDir.empty() && Config.BuildIdLinkInput)
|
||||
if (Error E =
|
||||
linkToBuildIdDir(Config, Config.InputFilename,
|
||||
Config.BuildIdLinkInput.getValue(), BuildIdBytes))
|
||||
return E;
|
||||
|
||||
if (Error E = handleArgs(Config, **Obj, Reader, OutputElfType))
|
||||
return createFileError(Config.InputFilename, std::move(E));
|
||||
|
||||
if (Error E = writeOutput(Config, **Obj, Out, OutputElfType))
|
||||
return createFileError(Config.InputFilename, std::move(E));
|
||||
if (!Config.BuildIdLinkDir.empty() && Config.BuildIdLinkOutput)
|
||||
if (Error E =
|
||||
linkToBuildIdDir(Config, Config.OutputFilename,
|
||||
Config.BuildIdLinkOutput.getValue(), BuildIdBytes))
|
||||
return createFileError(Config.OutputFilename, std::move(E));
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
@ -327,14 +327,12 @@ static Error isValidMachOCannonicalName(StringRef Name) {
|
||||
}
|
||||
|
||||
static Error handleArgs(const CopyConfig &Config, Object &Obj) {
|
||||
if (Config.AllowBrokenLinks || !Config.BuildIdLinkDir.empty() ||
|
||||
Config.BuildIdLinkInput || Config.BuildIdLinkOutput ||
|
||||
!Config.SplitDWO.empty() || !Config.SymbolsPrefix.empty() ||
|
||||
!Config.AllocSectionsPrefix.empty() || !Config.KeepSection.empty() ||
|
||||
Config.NewSymbolVisibility || !Config.SymbolsToGlobalize.empty() ||
|
||||
!Config.SymbolsToKeep.empty() || !Config.SymbolsToLocalize.empty() ||
|
||||
!Config.SymbolsToWeaken.empty() || !Config.SymbolsToKeepGlobal.empty() ||
|
||||
!Config.SectionsToRename.empty() ||
|
||||
if (Config.AllowBrokenLinks || !Config.SplitDWO.empty() ||
|
||||
!Config.SymbolsPrefix.empty() || !Config.AllocSectionsPrefix.empty() ||
|
||||
!Config.KeepSection.empty() || Config.NewSymbolVisibility ||
|
||||
!Config.SymbolsToGlobalize.empty() || !Config.SymbolsToKeep.empty() ||
|
||||
!Config.SymbolsToLocalize.empty() || !Config.SymbolsToWeaken.empty() ||
|
||||
!Config.SymbolsToKeepGlobal.empty() || !Config.SectionsToRename.empty() ||
|
||||
!Config.UnneededSymbolsToRemove.empty() ||
|
||||
!Config.SetSectionAlignment.empty() || !Config.SetSectionFlags.empty() ||
|
||||
Config.ExtractDWO || Config.LocalizeHidden || Config.PreserveDates ||
|
||||
|
@ -196,19 +196,6 @@ defm prefix_alloc_sections
|
||||
: Eq<"prefix-alloc-sections", "Add <prefix> to the start of every allocated section name">,
|
||||
MetaVarName<"prefix">;
|
||||
|
||||
defm build_id_link_dir
|
||||
: Eq<"build-id-link-dir", "Set directory for --build-id-link-input and "
|
||||
"--build-id-link-output to <dir>">,
|
||||
MetaVarName<"dir">;
|
||||
defm build_id_link_input
|
||||
: Eq<"build-id-link-input", "Hard-link the input to <dir>/xx/xxx<suffix> "
|
||||
"name derived from hex build ID">,
|
||||
MetaVarName<"suffix">;
|
||||
defm build_id_link_output
|
||||
: Eq<"build-id-link-output", "Hard-link the output to <dir>/xx/xxx<suffix> "
|
||||
"name derived from hex build ID">,
|
||||
MetaVarName<"suffix">;
|
||||
|
||||
defm set_start : Eq<"set-start", "Set the start address to <addr>. Overrides "
|
||||
"any previous --change-start or --adjust-start values.">,
|
||||
MetaVarName<"addr">;
|
||||
|
@ -72,10 +72,9 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj) {
|
||||
Obj.addSectionWithOwnedContents(Sec, std::move(Buf));
|
||||
}
|
||||
|
||||
if (!Config.AddGnuDebugLink.empty() || !Config.BuildIdLinkDir.empty() ||
|
||||
Config.BuildIdLinkInput || Config.BuildIdLinkOutput ||
|
||||
Config.ExtractPartition || !Config.SplitDWO.empty() ||
|
||||
!Config.SymbolsPrefix.empty() || !Config.AllocSectionsPrefix.empty() ||
|
||||
if (!Config.AddGnuDebugLink.empty() || Config.ExtractPartition ||
|
||||
!Config.SplitDWO.empty() || !Config.SymbolsPrefix.empty() ||
|
||||
!Config.AllocSectionsPrefix.empty() ||
|
||||
Config.DiscardMode != DiscardType::None || Config.NewSymbolVisibility ||
|
||||
!Config.SymbolsToAdd.empty() || !Config.RPathToAdd.empty() ||
|
||||
!Config.OnlySection.empty() || !Config.SymbolsToGlobalize.empty() ||
|
||||
|
Loading…
Reference in New Issue
Block a user