Commit Graph

13232 Commits

Author SHA1 Message Date
Arthur Eubanks 0b5051cede [llvm-reduce] Don't reuse SmallVector across calls to getAllMetadata()
The SmallVector is not cleared in calls to getAllMetadata().

Reviewed By: Meinersbur

Differential Revision: https://reviews.llvm.org/D113808
2021-11-15 14:53:48 -08:00
Steven Wan 351870720f [AIX][llvm-go] AIX linker does not recognize `-rpath`
The existing logic adds `-rpath` to CGO_LDFLAGS, which is not a valid linker option on AIX. This patch substitutes it with `-blibpath` on AIX.

Reviewed By: daltenty

Differential Revision: https://reviews.llvm.org/D113704
2021-11-15 13:13:08 -05:00
Lang Hames 55751f5f63 [llvm-jitlink] Add an explicit -debugger-support option.
Commit 69be352a19 restricted the MachO debugger support testcase to run on
Darwin only, but we still need to disable debugger support by default for
other noexec tests.

This patch introduces a -debugger-support option to llvm-jitlink that is
on-by-default when executing code, and off-by-default for noexec tests. This
should prevent regression tests from trying (and failing) to set up MachO
debugging support when running on non-Darwin platforms.

to explicitly enable/disable support.
2021-11-14 15:46:00 -08:00
Lang Hames 69be352a19 Reapply "[ORC] Initial MachO debugging support (via GDB JIT debug.." with fixes.
This reapplies e1933a0488 (which was reverted in
f55ba3525e due to bot failures, e.g.
https://lab.llvm.org/buildbot/#/builders/117/builds/2768).

The bot failures were due to a missing symbol error: We use the input object's
mangling to decide how to mangle the debug-info registration function name. This
caused lookup of the registration function to fail when the input object
mangling didn't match the host mangling.

Disbaling the test on non-Darwin platforms is the easiest short-term solution.
I have filed https://llvm.org/PR52503 with a proposed longer term solution.
2021-11-14 14:44:07 -08:00
Florian Hahn 4081df43b6
[llvm-reduce] Remove unnecessary loop.
After cd8aa234fd, there's no need to collect a vector of basic blocks
to keep first. Remove the first loop.
2021-11-14 21:03:21 +00:00
Lang Hames f55ba3525e Revert "[ORC] Initial MachO debugging support (via GDB JIT debug..."
This reverts commit e1933a0488 until I can look
into bot failures.
2021-11-14 00:14:39 -08:00
Lang Hames e1933a0488 [ORC] Initial MachO debugging support (via GDB JIT debug registration interface)
This commit adds a new plugin, GDBJITDebugInfoRegistrationPlugin, that checks
for objects containing debug info and registers any debug info found via the
GDB JIT registration API.

To enable this registration without redundantly representing non-debug sections
this plugin synthesizes a new embedded object within a section of the LinkGraph.
An allocation action is used to make the registration call.

Currently MachO only. ELF users can still use the DebugObjectManagerPlugin. The
two are likely to be merged in the near future.
2021-11-13 13:21:01 -08:00
Duncan P. N. Exon Smith 75c86c9935 Support: Make VarStreamArrayIterator iterate over const values
VarStreamArrayIterator returns a reference to a just-computed internal
value. Change it to iterate over `const ValueType` to avoid allowing
clients to mutate the internal state, and to drop the
non-`const`-qualified operator*().

The removed operator*() was from 175d70ee5c to get
iterator_facade_base::operator->() working, and this fixes the root
cause instead: setting `T` to `const ValueType` causes
iterator_facade_base to infer `PointerT` as `const ValueType*`.

Ironically, this is the last blocker for removing the const-incorrect
overload of `iterator_facade_base::operator->()`, whose presence
triggered adding the workaround in the first place :).

Differential Revision: https://reviews.llvm.org/D113797
2021-11-12 20:37:36 -08:00
Keith Smiley 47bb456b2f [llvm-obcopy][MachO] Add error for MH_PRELOAD
Previously this would crash. Fixes https://bugs.llvm.org/show_bug.cgi?id=51877

Differential Revision: https://reviews.llvm.org/D113819
2021-11-12 19:18:34 -08:00
wlei aab1810006 [llvm-profgen] Fix bug of setting function entry
Previously we set `isFuncEntry` flag  to true when the funcName from DWARF is equal to the name in symbol table and we use this flag to ignore reporting callsite sample that's from an intra func branch. However, in HHVM, it appears that the symbol table name is inconsistent with the dwarf info func name, it's likely due to `OptimizeGlobalAliases`.

This change is a workaround in llvm-profgen side to mark the only one range as the function entry and add warnings for the remaining inconsistence.

This also fixed a missing `getCanonicalFnName` for symbol name which caused the mismatching as well.

Reviewed By: hoy, wenlei

Differential Revision: https://reviews.llvm.org/D113492
2021-11-12 12:18:43 -08:00
Lang Hames 3fb641618f [ORC-RT][llvm-jitlink] Fix a buggy check in ORC-RT MachO TLV deregistration.
The check was failing because it was matching against the end of the range, not
the start.

This bug wasn't causing the ORC-RT MachO TLV regression test to fail because
we were only logging deallocation errors (including TLV deregistration errors)
and not actually returning a failure code. This commit updates llvm-jitlink to
report the errors properly.
2021-11-12 10:36:17 -08:00
Tomasz Miąsko c3e07df607 [llvm-nm] Demangle Rust symbols
Add support for demangling Rust v0 symbols to llvm-nm by reusing
nonMicrosoftDemangle which supports both Itanium and Rust mangling.

Reviewed By: dblaikie, jhenderson

Differential Revision: https://reviews.llvm.org/D111937
2021-11-12 12:46:59 +01:00
Arthur Eubanks 87687b4ff7 [llvm-reduce] Fix build after D113537
Forgot to amend D113537 with these changes before committing.
2021-11-11 18:53:34 -08:00
Arthur Eubanks 6f288bd772 [llvm-reduce] Count chunks by running a preliminary reduction
Having a separate counting method runs the risk of a mismatch between
the actual reduction method and the counting method.

Instead, create an Oracle that always returns true for shouldKeep(), run
the reduction, and count how many times shouldKeep() was called. The
module should not be modified if shouldKeep() always returns true.

Reviewed By: Meinersbur

Differential Revision: https://reviews.llvm.org/D113537
2021-11-11 18:46:09 -08:00
Arthur Eubanks be0b47d530 [llvm-reduce] Skip replacing metadata and callee operands
Metadata operands tend to require special conditions, especially on dbg
intrinsics. We also don't have a zero value for metadata.

Replacing callee operands is a little weird, since calling undef/null
doesn't make sense. It also causes tons of invalid reductions when
reducing calls to intrinsics since only arguments to intrinsics can be
of the metadata type.

Reviewed By: Meinersbur

Differential Revision: https://reviews.llvm.org/D113532
2021-11-11 18:42:16 -08:00
Michael Kruse c15f930e96 [llvm-reduce] Introduce operands-skip pass.
Add a new "operands-skip" pass whose goal is to remove instructions in the middle of dependency chains. For instance:
```
  %baseptr = alloca i32
  %arrayidx = getelementptr i32, i32* %baseptr, i32 %idxprom
  store i32 42, i32* %arrayidx
```
might be reducible to
```
  %baseptr = alloca i32
  %arrayidx = getelementptr ...  ; now dead, together with the computation of %idxprom
  store i32 42, i32* %baseptr
```
Other passes would either replace `%baseptr` with undef (operands, instructions) or move it to become a function argument (operands-to-args), both of which might fail the interestingness check.

In principle the implementation allows operand replacement with any value or instruction in the function that passes the filter constraints (same type, dominance, "more reduced"), but is limited in this patch to values that are directly or indirectly used to compute the current operand value, motivated by the example above. Additionally, function arguments are added to the candidate set which helps reducing the number of relevant arguments mitigating a concern of too many arguments mentioned in https://reviews.llvm.org/D110274#3025013.

Possible future extensions:
 * Instead of requiring the same type, bitcast/trunc/zext could be automatically inserted for some more flexibility.
 * If undef is added to the candidate set, "operands-skip"is able to produce any reduction that "operands" can do. Additional candidates might be zero and one, where the "reductive power" classification can prefer one over the other. If undefined behaviour should not be introduced, undef can be removed from the candidate set.

Recommit after resolving conflict with D112651 and reusing
shouldReduceOperand from D113532.

Reviewed By: aeubanks

Differential Revision: https://reviews.llvm.org/D111818
2021-11-11 20:16:34 -06:00
Michael Kruse ed7b37155b Revert "[llvm-reduce] Introduce operands-skip pass."
This reverts commit fa4210a9a0.

It causes compile failures, presumably because conflicting with another
patch landed after I checked locally.
2021-11-11 19:25:39 -06:00
Michael Kruse fa4210a9a0 [llvm-reduce] Introduce operands-skip pass.
Add a new "operands-skip" pass whose goal is to remove instructions in the middle of dependency chains. For instance:
```
  %baseptr = alloca i32
  %arrayidx = getelementptr i32, i32* %baseptr, i32 %idxprom
  store i32 42, i32* %arrayidx
```
might be reducible to
```
  %baseptr = alloca i32
  %arrayidx = getelementptr ...  ; now dead, together with the computation of %idxprom
  store i32 42, i32* %baseptr
```
Other passes would either replace `%baseptr` with undef (operands, instructions) or move it to become a function argument (operands-to-args), both of which might fail the interestingness check.

In principle the implementation allows operand replacement with any value or instruction in the function that passes the filter constraints (same type, dominance, "more reduced"), but is limited in this patch to values that are directly or indirectly used to compute the current operand value, motivated by the example above. Additionally, function arguments are added to the candidate set which helps reducing the number of relevant arguments mitigating a concern of too many arguments mentioned in https://reviews.llvm.org/D110274#3025013.

Possible future extensions:
 * Instead of requiring the same type, bitcast/trunc/zext could be automatically inserted for some more flexibility.
 * If undef is added to the candidate set, "operands-skip"is able to produce any reduction that "operands" can do. Additional candidates might be zero and one, where the "reductive power" classification can prefer one over the other. If undefined behaviour should not be introduced, undef can be removed from the candidate set.

Reviewed By: aeubanks

Differential Revision: https://reviews.llvm.org/D111818
2021-11-11 18:54:01 -06:00
Florian Hahn cd8aa234fd
[llvm-reduce] Use DenseSet instead of std::set (NFC).
When reducing functions with very large basic blocks (~ almost 1 million
BBs), the majority of time is spent maintaining the order in the std::set
for the basic blocks to keep.

In those cases, DenseSet<> is much more efficient. Use it instead.
2021-11-10 13:56:22 +00:00
Martin Storsjö 91350eb151 [llvm-objdump] Remove a trailing semicolon, fixing GCC warnings. NFC. 2021-11-10 09:39:47 +02:00
Arthur Eubanks b394ba5d7f [llvm-reduce] Print extra newline when encountering unknown pass 2021-11-09 15:20:16 -08:00
Luís Ferreira 9af467ed8b [Tools] Add a fuzzing tool to help fuzzing D demangler
This patch adds a fuzzing helper tool for D demangler by feeding the demangler API with
pseudo-random null terminated strings with the help of libfuzzer heuristics.

Reviewed By: dblaikie

Differential Revision: https://reviews.llvm.org/D111432
2021-11-09 12:45:25 -08:00
Dwight Guth 16c3db8def [llvm-reduce] Fix invalid reduction in basic-blocks delta pass
Previously, if the basic-blocks delta pass tried to remove a basic block
that was the last basic block in a function that did not have external
or weak linkage, the resulting IR would become invalid. Since removing
the last basic block in a function is effectively identical to removing
the function body itself, we check explicitly for this case and if we
detect it, we run the same logic as in ReduceFunctionBodies.cpp

Reviewed By: aeubanks

Differential Revision: https://reviews.llvm.org/D113486
2021-11-09 10:43:38 -08:00
Dwight Guth fbfd327fdf [llvm-reduce] Add flag to start at finer granularity
Sometimes if llvm-reduce is interrupted in the middle of a delta pass on
a large file, it can take quite some time for the tool to start actually
doing new work if it is restarted again on the partially-reduced file. A
lot of time ends up being spent testing large chunks when these large
chunks are very unlikely to actually pass the interestingness test. In
cases like this, the tool will complete faster if the starting
granularity is reduced to a finer amount. Thus, we introduce a command
line flag that automatically divides the chunks into smaller subsets a
fixed, user-specified number of times prior to beginning the core loop.

Reviewed By: aeubanks

Differential Revision: https://reviews.llvm.org/D112651
2021-11-09 10:14:08 -08:00
Fangrui Song 5f1e509579 [llvm-objdump] -p: Dump PE header for PE/COFF
For a trivial DLL built with `clang --target=x86_64-windows -O2 -c a.c; lld-link -subsystem:console -dll a.o -out:a.dll`,
`objdump -p` vs `llvm-objdump -p`:

```
-a.dll:     file format pei-x86-64
-
+a.dll: file format coff-x86-64
 Characteristics 0x2022
        executable
        large address aware
@@ -57,4 +56,4 @@
 Entry d 0000000000000000 00000000 Delay Import Directory
 Entry e 0000000000000000 00000000 CLR Runtime Header
 Entry f 0000000000000000 00000000 Reserved
-
+Export Table:
```

For a Linux image (`vmlinuz-5.10.76-gentoo-r1`) built with `CONFIG_EFI_STUB=y`

```
-vmlinuz-5.10.76-gentoo-r1:     file format pei-x86-64
-
-Characteristics 0x20e
+vmlinuz-5.10.76-gentoo-r1:     file format coff-x86-64
+Characteristics 0x206
        executable
        line numbers stripped
-       symbols stripped
        debugging information removed

 Time/Date              Wed Dec 31 16:00:00 1969
@@ -55,10 +53,4 @@
 Entry d 0000000000000000 00000000 Delay Import Directory
 Entry e 0000000000000000 00000000 CLR Runtime Header
 Entry f 0000000000000000 00000000 Reserved
-
-
-PE File Base Relocations (interpreted .reloc section contents)
-
-Virtual Address: 000037ca Chunk size 10 (0xa) Number of fixups 1
-       reloc    0 offset    0 [37ca] ABSOLUTE
-
+Export Table:
```

`symbols stripped` looks like a GNU objdump problem.

Reviewed By: jhenderson, alexander-shaposhnikov

Differential Revision: https://reviews.llvm.org/D113356
2021-11-09 10:08:41 -08:00
Paul Robinson 38be8f4057 Add llvm-tli-checker
A new tool that compares TargetLibraryInfo's opinion of the availability
of library function calls against the functions actually exported by a
specified set of libraries. Can be helpful in verifying the correctness
of TLI for a given target, and avoid mishaps such as had to be addressed
in D107509 and 94b4598d.

The tool currently supports ELF object files only, although it's unlikely
to be hard to add support for other formats.

Re-commits 62dd488 with changes to use pre-generated objects, as not all
bots have ld.lld available.

Differential Revision: https://reviews.llvm.org/D111358
2021-11-08 16:29:28 -08:00
Paul Robinson 1297c21406 Revert "Add llvm-tli-checker"
Not all bots have ld.lld available.
This reverts commit 62dd488164.
2021-11-08 15:48:29 -08:00
Jessica Clarke a9a510f217 [bugpoint] Fix repeated off-by-one error in debug output
This resulted in the final argument being dropped from the output, which
can be rather important.
2021-11-08 23:44:45 +00:00
Paul Robinson 62dd488164 Add llvm-tli-checker
A new tool that compares TargetLibraryInfo's opinion of the availability
of library function calls against the functions actually exported by a
specified set of libraries. Can be helpful in verifying the correctness
of TLI for a given target, and avoid mishaps such as had to be addressed
in D107509 and 94b4598d.

The tool currently supports ELF object files only, although it's unlikely
to be hard to add support for other formats.

Differential Revision: https://reviews.llvm.org/D111358
2021-11-08 14:59:13 -08:00
Adrian Prantl fae440974a Attempt to work around type checking error on older compilers 2021-11-08 12:42:33 -08:00
Adrian Prantl 8bd8dd16e2 Extend obj2yaml to optionally preserve raw __LINKEDIT/__DATA segments.
I am planning to upstream MachOObjectFile code to support Darwin
chained fixups. In order to test the new parser features we need a way
to produce correct (and incorrect) chained fixups. Right now the only
tool that can produce them is the Darwin linker. To avoid having to
check in binary files, this patch allows obj2yaml to print a hexdump
of the raw LINKEDIT and DATA segment, which both allows to
bootstrap the parser and enables us to easily create malformed inputs
to test error handling in the parser.

This patch adds two new options to obj2yaml:

  -raw-data-segment
  -raw-linkedit-segment

Differential Revision: https://reviews.llvm.org/D113234
2021-11-08 11:30:12 -08:00
Roger Kim 1658980a1c [NFC][llvm-libtool-darwin] Clean up names
Removing unclear abbreviations.

Reviewed By: jhenderson

Differential Revision: https://reviews.llvm.org/D113215
2021-11-08 10:33:59 -08:00
Roger Kim c51f947a13 [NFC][llvm-libtool-darwin] Remove unnecessary conditionals around errors
The existing code has unnecessary logic to indirectly pass
errors through function calls. This diff gets rid of the fluff.

Test Plan: Existing unit tests

Reviewed By: jhenderson, drodriguez, alexander-shaposhnikov

Differential Revision: https://reviews.llvm.org/D113301
2021-11-08 10:33:52 -08:00
Zarko Todorovski c4396b77ae [LLVM][llvm-cfi] Inclusive language: replace uses of blacklist with ignorelist
Replace the description and file names for this argument. As far as I understand
this is a positional argument and I don't believe this changes breaks any existing
interfaces.

Reviewed By: hctim, MaskRay

Differential Revision: https://reviews.llvm.org/D113316
2021-11-08 10:05:52 -05:00
Esme-Yi 9b6f264d2b [XCOFF][llvm-readobj] improve the relocation output.
Summary:
	1. implemented the unexpanded relocations output.
	2. modified the expanded output format to align.

Reviewed By: shchenz, jhenderson

Differential Revision: https://reviews.llvm.org/D111700
2021-11-08 03:15:52 +00:00
Fangrui Song 859a6d973f [llvm-objdump] Remove untested diagnostic "missing data dir for TLS table" 2021-11-06 11:18:29 -07:00
Kazu Hirata 87e53a0ad8 [llvm] Use make_early_inc_range (NFC) 2021-11-05 19:39:07 -07:00
wlei 5bf191a381 [llvm-profgen] Fix index out of bounds error while using ip.advance
Previously we assume there're some non-executing sections at the bottom of the text section so that we won't hit the array's bound. But on BOLTed binary, it turned out .bolt section is at the bottom of text section which can be profiled, then it crash llvm-profgen. This change try to fix it.

Reviewed By: hoy, wenlei

Differential Revision: https://reviews.llvm.org/D113238
2021-11-05 18:38:40 -07:00
Fangrui Song 26a8ceba3e [llvm-readobj] Display DT_RELRSZ/DT_RELRENT as " (bytes)"
to match RELSZ/RELENT.

Reviewed By: jhenderson

Differential Revision: https://reviews.llvm.org/D113206
2021-11-05 10:02:49 -07:00
Roman Lebedev 7a98761d74
[NFC] Move CombinationGenerator from Exegesis to ADT
Reviewed By: courbet

Differential Revision: https://reviews.llvm.org/D113213
2021-11-05 16:53:46 +03:00
Quinn Pham c71fbdd87b [NFC] Inclusive language: Remove instances of master in URLs
[NFC] This patch fixes URLs containing "master". Old URLs were either broken or
redirecting to the new URL.

Reviewed By: #libc, ldionne, mehdi_amini

Differential Revision: https://reviews.llvm.org/D113186
2021-11-05 08:48:41 -05:00
Arthur Eubanks 13317286f8 [NewPM] Use the default AA pipeline by default
We almost always want to use the default AA pipeline. It's very easy for
users of PassBuilder to forget to customize the AAManager to use the
default AA pipeline (for example, the NewPM C API forgets to do this).

If somebody wants a custom AA pipeline, similar to what is being done
now with the default AA pipeline registration, they can

  FAM.registerPass([&] { return std::move(MyAA); });

before calling

  PB.registerFunctionAnalyses(FAM);

For example, LTOBackend.cpp and NewPMDriver.cpp do this.

Reviewed By: asbirlea

Differential Revision: https://reviews.llvm.org/D113210
2021-11-04 15:10:34 -07:00
Ben Langmuir a2639dcbe6 [ORC] Add a utility for adding missing "self" relocations to a Symbol
If a tool wants to introduce new indirections via stubs at link-time in
ORC, it can cause fidelity issues around the address of the function if
some references to the function do not have relocations. This is known
to happen inside the body of the function itself on x86_64 for example,
where a PC-relative address is formed, but without a relocation.

```
_foo:
  leaq -7(%rip), %rax ## form pointer to '_foo' without relocation

_bar:
  leaq (%rip), %rax ##  uses X86_64_RELOC_SIGNED to '_foo'
```

The consequence of introducing a stub for such a function at link time
is that if it forms a pointer to itself without relocation, it will not
have the same value as a pointer from outside the function. If the
function pointer is used as a key, this can cause problems.

This utility provides best-effort support for adding such missing
relocations using MCDisassembler and MCInstrAnalysis to identify the
problematic instructions. Currently it is only implemented for x86_64.

Note: the related issue with call/jump instructions is not handled
here, only forming function pointers.

rdar://83514317

Differential revision: https://reviews.llvm.org/D113038
2021-11-04 15:01:05 -07:00
Noah Shutty d788c44f5c [Support] Improve Caching conformance with Support library behavior
This diff makes several amendments to the local file caching mechanism
which was migrated from ThinLTO to Support in
rGe678c51177102845c93529d457b020f969125373 in response to follow-up
discussion on that commit.

Patch By: noajshu

Differential Revision: https://reviews.llvm.org/D113080
2021-11-04 13:00:44 -07:00
Rahman Lavaee f533ec37eb Make the BBAddrMap struct binary-format-agnostic.
The only binary-format-related field in the BBAddrMap structure is the function address (`Addr`), which will use uint64_t in 64B format and uint32_t in 32B format. This patch changes it to use uint64_t in both formats.
This allows non-templated use of the struct, at the expense of a marginal additional size overhead for the 32-bit format. The size of the BB address map section does not change.

Differential Revision: https://reviews.llvm.org/D112679
2021-11-04 10:27:24 -07:00
gbreynoo ced9287c2d [llvm-objdump] Fix the Assertion failure when providing invalid --debug-vars or --dwarf values
As seen in https://bugs.llvm.org/show_bug.cgi?id=52213 llvm-objdump
asserts if either the --debug-vars or the --dwarf options are provided
with invalid values. As suggested, this fix adds use of a default value
to these options and errors when given bad input.

Differential Revision: https://reviews.llvm.org/D112183
2021-11-04 11:01:32 +00:00
Jakub Kuderski 3348b841d3 Make enum iteration with seq safe by default
By default `llvm::seq` would happily iterate over enums, which may be unsafe if the enum values are not continuous. This patch disable enum iteration with `llvm::seq` and `llvm::seq_inclusive` and adds two new functions: `enum_seq` and `enum_seq_inclusive`.

To make sure enum iteration is safe, we require users to declare their enum types as iterable by specializing `enum_iteration_traits<SomeEnum>`. Because it's not always possible to add these traits next to enum definition (e.g., for enums defined in external libraries), we provide an escape hatch to allow iteration on per-callsite basis by passing `force_iteration_on_noniterable_enum`.

The main benefit of this approach is that these global declarations via traits can appear just next to enum definitions, making easy to spot when enums are miss-labeled, e.g., after introducing new enum values, whereas `force_iteration_on_noniterable_enum` should stand out and be easy to grep for.

This emerged from a discussion with gchatelet@ about reusing llvm's `Sequence.h` in lieu of https://github.com/GPUOpen-Drivers/llpc/blob/dev/lgc/interface/lgc/EnumIterator.h.

Reviewed By: dblaikie, gchatelet, aaron.ballman

Differential Revision: https://reviews.llvm.org/D107378
2021-11-03 20:52:21 -04:00
Kirill Stoimenov a55c4ec1ce [ASan] Process functions in Asan module pass
This came up as recommendation while reviewing D112098.

Reviewed By: vitalybuka

Differential Revision: https://reviews.llvm.org/D112732
2021-11-03 20:27:53 +00:00
Vitaly Buka 3131714f8d [NFC][asan] Use AddressSanitizerOptions in ModuleAddressSanitizerPass
Reviewed By: kstoimenov

Differential Revision: https://reviews.llvm.org/D113072
2021-11-03 11:32:14 -07:00
Kirill Stoimenov b3145323b5 Revert "[ASan] Process functions in Asan module pass"
This reverts commit 76ea87b94e.

Reviewed By: kstoimenov

Differential Revision: https://reviews.llvm.org/D113129
2021-11-03 18:01:01 +00:00