diff --git a/llvm/include/llvm/Object/ELFObjectFile.h b/llvm/include/llvm/Object/ELFObjectFile.h
--- a/llvm/include/llvm/Object/ELFObjectFile.h
+++ b/llvm/include/llvm/Object/ELFObjectFile.h
@@ -64,6 +64,7 @@
   virtual uint64_t getSectionOffset(DataRefImpl Sec) const = 0;
 
   virtual Expected<int64_t> getRelocationAddend(DataRefImpl Rel) const = 0;
+  virtual int64_t getOptionalRelocationAddend(DataRefImpl Rel) const = 0;
   virtual Error getBuildAttributes(ELFAttributeParser &Attributes) const = 0;
 
 public:
@@ -198,6 +199,10 @@
   Expected<int64_t> getAddend() const {
     return getObject()->getRelocationAddend(getRawDataRefImpl());
   }
+
+  int64_t getOptionalAddend() const {
+    return getObject()->getOptionalRelocationAddend(getRawDataRefImpl());
+  }
 };
 
 class elf_relocation_iterator : public relocation_iterator {
@@ -423,6 +428,7 @@
   section_iterator section_end() const override;
 
   Expected<int64_t> getRelocationAddend(DataRefImpl Rel) const override;
+  int64_t getOptionalRelocationAddend(DataRefImpl Rel) const override;
 
   uint8_t getBytesInAddress() const override;
   StringRef getFileFormatName() const override;
@@ -949,6 +955,14 @@
 }
 
 template <class ELFT>
+int64_t
+ELFObjectFile<ELFT>::getOptionalRelocationAddend(DataRefImpl Rel) const {
+  if (getRelSection(Rel)->sh_type != ELF::SHT_RELA)
+    return 0;
+  return (int64_t)getRela(Rel)->r_addend;
+}
+
+template <class ELFT>
 const typename ELFObjectFile<ELFT>::Elf_Rel *
 ELFObjectFile<ELFT>::getRel(DataRefImpl Rel) const {
   assert(getRelSection(Rel)->sh_type == ELF::SHT_REL);
diff --git a/llvm/lib/XRay/InstrumentationMap.cpp b/llvm/lib/XRay/InstrumentationMap.cpp
--- a/llvm/lib/XRay/InstrumentationMap.cpp
+++ b/llvm/lib/XRay/InstrumentationMap.cpp
@@ -52,18 +52,20 @@
 
 static Error
 loadObj(StringRef Filename, object::OwningBinary<object::ObjectFile> &ObjFile,
-          InstrumentationMap::SledContainer &Sleds,
-          InstrumentationMap::FunctionAddressMap &FunctionAddresses,
-          InstrumentationMap::FunctionAddressReverseMap &FunctionIds) {
+        InstrumentationMap::SledContainer &Sleds,
+        InstrumentationMap::FunctionAddressMap &FunctionAddresses,
+        InstrumentationMap::FunctionAddressReverseMap &FunctionIds) {
   InstrumentationMap Map;
 
   // Find the section named "xray_instr_map".
   if ((!ObjFile.getBinary()->isELF() && !ObjFile.getBinary()->isMachO()) ||
       !(ObjFile.getBinary()->getArch() == Triple::x86_64 ||
         ObjFile.getBinary()->getArch() == Triple::ppc64le ||
+        ObjFile.getBinary()->getArch() == Triple::arm ||
         ObjFile.getBinary()->getArch() == Triple::aarch64))
     return make_error<StringError>(
-        "File format not supported (only does ELF and Mach-O little endian 64-bit).",
+        Twine("File format not supported.  Supports: "
+              "AArch64/ARM/ppc64le/x86-64."),
         std::make_error_code(std::errc::not_supported));
 
   StringRef Contents = "";
@@ -94,11 +96,14 @@
     uint32_t RelativeRelocation = [](object::ObjectFile *ObjFile) {
       if (const auto *ELFObj = dyn_cast<object::ELF32LEObjectFile>(ObjFile))
         return ELFObj->getELFFile()->getRelativeRelocationType();
-      else if (const auto *ELFObj = dyn_cast<object::ELF32BEObjectFile>(ObjFile))
+      else if (const auto *ELFObj =
+                   dyn_cast<object::ELF32BEObjectFile>(ObjFile))
         return ELFObj->getELFFile()->getRelativeRelocationType();
-      else if (const auto *ELFObj = dyn_cast<object::ELF64LEObjectFile>(ObjFile))
+      else if (const auto *ELFObj =
+                   dyn_cast<object::ELF64LEObjectFile>(ObjFile))
         return ELFObj->getELFFile()->getRelativeRelocationType();
-      else if (const auto *ELFObj = dyn_cast<object::ELF64BEObjectFile>(ObjFile))
+      else if (const auto *ELFObj =
+                   dyn_cast<object::ELF64BEObjectFile>(ObjFile))
         return ELFObj->getELFFile()->getRelativeRelocationType();
       else
         return static_cast<uint32_t>(0);
@@ -112,16 +117,15 @@
     for (const object::SectionRef &Section : Sections) {
       for (const object::RelocationRef &Reloc : Section.relocations()) {
         if (SupportsRelocation && SupportsRelocation(Reloc.getType())) {
-          auto AddendOrErr = object::ELFRelocationRef(Reloc).getAddend();
-          auto A = AddendOrErr ? *AddendOrErr : 0;
+          auto A = object::ELFRelocationRef(Reloc).getOptionalAddend();
           Expected<uint64_t> ValueOrErr = Reloc.getSymbol()->getValue();
           if (!ValueOrErr)
             // TODO: Test this error.
             return ValueOrErr.takeError();
           Relocs.insert({Reloc.getOffset(), Resolver(Reloc, *ValueOrErr, A)});
         } else if (Reloc.getType() == RelativeRelocation) {
-          if (auto AddendOrErr = object::ELFRelocationRef(Reloc).getAddend())
-            Relocs.insert({Reloc.getOffset(), *AddendOrErr});
+          auto A = object::ELFRelocationRef(Reloc).getOptionalAddend();
+          Relocs.insert({Reloc.getOffset(), A});
         }
       }
     }
@@ -129,12 +133,13 @@
 
   // Copy the instrumentation map data into the Sleds data structure.
   auto C = Contents.bytes_begin();
-  static constexpr size_t ELF64SledEntrySize = 32;
+  bool Is32Bit = ObjFile.getBinary()->makeTriple().isArch32Bit();
+  size_t ELFSledEntrySize = Is32Bit ? 16 : 32;
 
-  if ((C - Contents.bytes_end()) % ELF64SledEntrySize != 0)
+  if ((C - Contents.bytes_end()) % ELFSledEntrySize != 0)
     return make_error<StringError>(
         Twine("Instrumentation map entries not evenly divisible by size of "
-              "an XRay sled entry in ELF64."),
+              "an XRay sled entry."),
         std::make_error_code(std::errc::executable_format_error));
 
   auto RelocateOrElse = [&](uint64_t Offset, uint64_t Address) {
@@ -147,20 +152,26 @@
     return Address;
   };
 
-  const int WordSize = 8;
+  const int WordSize = Is32Bit ? 4 : 8;
   int32_t FuncId = 1;
   uint64_t CurFn = 0;
-  for (; C != Contents.bytes_end(); C += ELF64SledEntrySize) {
+  for (; C != Contents.bytes_end(); C += ELFSledEntrySize) {
     DataExtractor Extractor(
-        StringRef(reinterpret_cast<const char *>(C), ELF64SledEntrySize), true,
+        StringRef(reinterpret_cast<const char *>(C), ELFSledEntrySize), true,
         8);
     Sleds.push_back({});
     auto &Entry = Sleds.back();
     uint64_t OffsetPtr = 0;
     uint64_t AddrOff = OffsetPtr;
-    Entry.Address = RelocateOrElse(AddrOff, Extractor.getU64(&OffsetPtr));
+    if (Is32Bit)
+      Entry.Address = RelocateOrElse(AddrOff, Extractor.getU32(&OffsetPtr));
+    else
+      Entry.Address = RelocateOrElse(AddrOff, Extractor.getU64(&OffsetPtr));
     uint64_t FuncOff = OffsetPtr;
-    Entry.Function = RelocateOrElse(FuncOff, Extractor.getU64(&OffsetPtr));
+    if (Is32Bit)
+      Entry.Function = RelocateOrElse(FuncOff, Extractor.getU32(&OffsetPtr));
+    else
+      Entry.Function = RelocateOrElse(FuncOff, Extractor.getU64(&OffsetPtr));
     auto Kind = Extractor.getU8(&OffsetPtr);
     static constexpr SledEntry::FunctionKinds Kinds[] = {
         SledEntry::FunctionKinds::ENTRY, SledEntry::FunctionKinds::EXIT,
@@ -240,7 +251,8 @@
   if (!ObjectFileOrError) {
     auto E = ObjectFileOrError.takeError();
     // We try to load it as YAML if the ELF load didn't work.
-    Expected<sys::fs::file_t> FdOrErr = sys::fs::openNativeFileForRead(Filename);
+    Expected<sys::fs::file_t> FdOrErr =
+        sys::fs::openNativeFileForRead(Filename);
     if (!FdOrErr) {
       // Report the ELF load error if YAML failed.
       consumeError(FdOrErr.takeError());
@@ -262,7 +274,7 @@
                           Map.FunctionAddresses, Map.FunctionIds))
       return std::move(E);
   } else if (auto E = loadObj(Filename, *ObjectFileOrError, Map.Sleds,
-                                Map.FunctionAddresses, Map.FunctionIds)) {
+                              Map.FunctionAddresses, Map.FunctionIds)) {
     return std::move(E);
   }
   return Map;
diff --git a/llvm/test/tools/llvm-xray/ARM/Inputs/elf32-pic.yaml b/llvm/test/tools/llvm-xray/ARM/Inputs/elf32-pic.yaml
new file mode 100644
--- /dev/null
+++ b/llvm/test/tools/llvm-xray/ARM/Inputs/elf32-pic.yaml
@@ -0,0 +1,204 @@
+# Generated from the following source:
+# __attribute__((xray_always_instrument)) void foo() {}
+# __attribute__((xray_always_instrument)) void bar() {}
+# __attribute__((xray_always_instrument)) void jar() {}
+
+# Built with the following arguments:
+# -target armv7a-linux-androideabi -nostdlib -fxray-instrument -fPIC -shared
+
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS32
+  Data:            ELFDATA2LSB
+  Type:            ET_DYN
+  Machine:         EM_ARM
+  Flags:           [ EF_ARM_SOFT_FLOAT, EF_ARM_EABI_VER5 ]
+  Entry:           0x00000000000012B0
+ProgramHeaders:
+  - Type:            PT_PHDR
+    Flags:           [ PF_R ]
+    VAddr:           0x0000000000000034
+    Align:           0x0000000000000004
+  - Type:            PT_LOAD
+    Flags:           [ PF_R ]
+    Sections:
+      - Section:         .dynsym
+      - Section:         .hash
+      - Section:         .dynstr
+      - Section:         .rel.dyn
+    Align:           0x0000000000001000
+  - Type:            PT_LOAD
+    Flags:           [ PF_X, PF_R ]
+    Sections:
+      - Section:         .text
+    VAddr:           0x00000000000012B0
+    Align:           0x0000000000001000
+  - Type:            PT_LOAD
+    Flags:           [ PF_W, PF_R ]
+    Sections:
+      - Section:         .dynamic
+    VAddr:           0x0000000000002364
+    Align:           0x0000000000001000
+  - Type:            PT_LOAD
+    Flags:           [ PF_W, PF_R ]
+    Sections:
+      - Section:         xray_instr_map
+      - Section:         xray_fn_idx
+    VAddr:           0x00000000000033CC
+    Align:           0x0000000000001000
+  - Type:            PT_DYNAMIC
+    Flags:           [ PF_W, PF_R ]
+    Sections:
+      - Section:         .dynamic
+    VAddr:           0x0000000000002364
+    Align:           0x0000000000000004
+  - Type:            PT_GNU_RELRO
+    Flags:           [ PF_R ]
+    Sections:
+      - Section:         .dynamic
+    VAddr:           0x0000000000002364
+  - Type:            PT_GNU_STACK
+    Flags:           [ PF_W, PF_R ]
+    Align:           0x0000000000000000
+Sections:
+  - Name:            .dynsym
+    Type:            SHT_DYNSYM
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x0000000000000154
+    Link:            .dynstr
+    AddressAlign:    0x0000000000000004
+    EntSize:         0x0000000000000010
+  - Name:            .hash
+    Type:            SHT_HASH
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x00000000000001BC
+    Link:            .dynsym
+    AddressAlign:    0x0000000000000004
+    EntSize:         0x0000000000000004
+    Bucket:          [ 0, 0, 3, 0 ]
+    Chain:           [ 0, 0, 1, 2 ]
+  - Name:            .dynstr
+    Type:            SHT_STRTAB
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x00000000000001E4
+    AddressAlign:    0x0000000000000001
+  - Name:            .rel.dyn
+    Type:            SHT_REL
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x0000000000000200
+    Link:            .dynsym
+    AddressAlign:    0x0000000000000004
+    Relocations:
+      - Offset:          0x00000000000033CC
+        Type:            R_ARM_RELATIVE
+      - Offset:          0x00000000000033DC
+        Type:            R_ARM_RELATIVE
+      - Offset:          0x00000000000033EC
+        Type:            R_ARM_RELATIVE
+      - Offset:          0x00000000000033FC
+        Type:            R_ARM_RELATIVE
+      - Offset:          0x000000000000340C
+        Type:            R_ARM_RELATIVE
+      - Offset:          0x000000000000341C
+        Type:            R_ARM_RELATIVE
+      - Offset:          0x0000000000003430
+        Type:            R_ARM_RELATIVE
+      - Offset:          0x0000000000003434
+        Type:            R_ARM_RELATIVE
+      - Offset:          0x0000000000003438
+        Type:            R_ARM_RELATIVE
+      - Offset:          0x000000000000343C
+        Type:            R_ARM_RELATIVE
+      - Offset:          0x0000000000003440
+        Type:            R_ARM_RELATIVE
+      - Offset:          0x0000000000003444
+        Type:            R_ARM_RELATIVE
+      - Offset:          0x00000000000033F0
+        Symbol:          _Z3barv
+        Type:            R_ARM_ABS32
+      - Offset:          0x0000000000003400
+        Symbol:          _Z3barv
+        Type:            R_ARM_ABS32
+      - Offset:          0x00000000000033D0
+        Symbol:          _Z3foov
+        Type:            R_ARM_ABS32
+      - Offset:          0x00000000000033E0
+        Symbol:          _Z3foov
+        Type:            R_ARM_ABS32
+      - Offset:          0x0000000000003410
+        Symbol:          _Z3jarv
+        Type:            R_ARM_ABS32
+      - Offset:          0x0000000000003420
+        Symbol:          _Z3jarv
+        Type:            R_ARM_ABS32
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:         0x00000000000012B0
+    AddressAlign:    0x0000000000000004
+    Content:         050000EA00F020E300F020E300F020E300F020E300F020E300F020E3050000EA00F020E300F020E300F020E300F020E300F020E300F020E31EFF2FE1050000EA00F020E300F020E300F020E300F020E300F020E300F020E3050000EA00F020E300F020E300F020E300F020E300F020E300F020E31EFF2FE1050000EA00F020E300F020E300F020E300F020E300F020E300F020E3050000EA00F020E300F020E300F020E300F020E300F020E300F020E31EFF2FE1
+  - Name:            .dynamic
+    Type:            SHT_DYNAMIC
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    Address:         0x0000000000002364
+    Link:            .dynstr
+    AddressAlign:    0x0000000000000004
+    Entries:
+      - Tag:             DT_FLAGS
+        Value:           0x0000000000000008
+      - Tag:             DT_FLAGS_1
+        Value:           0x0000000000000001
+      - Tag:             DT_REL
+        Value:           0x0000000000000200
+      - Tag:             DT_RELSZ
+        Value:           0x0000000000000090
+      - Tag:             DT_RELENT
+        Value:           0x0000000000000008
+      - Tag:             DT_RELCOUNT
+        Value:           0x000000000000000C
+      - Tag:             DT_SYMTAB
+        Value:           0x0000000000000154
+      - Tag:             DT_SYMENT
+        Value:           0x0000000000000010
+      - Tag:             DT_STRTAB
+        Value:           0x00000000000001E4
+      - Tag:             DT_STRSZ
+        Value:           0x0000000000000019
+      - Tag:             DT_HASH
+        Value:           0x00000000000001BC
+      - Tag:             DT_NULL
+        Value:           0x0000000000000000
+  - Name:            xray_instr_map
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC, SHF_LINK_ORDER ]
+    Address:         0x00000000000033CC
+    Link:            .text
+    AddressAlign:    0x0000000000000001
+    Content:         B0120000000000000001000000000000CC120000000000000101000000000000EC120000000000000001000000000000081300000000000001010000000000002813000000000000000100000000000044130000000000000101000000000000
+  - Name:            xray_fn_idx
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC, SHF_LINK_ORDER ]
+    Address:         0x0000000000003430
+    Link:            .text
+    AddressAlign:    0x0000000000000008
+    Content:         CC330000EC330000EC3300000C3400000C3400002C340000
+DynamicSymbols:
+  - Name:            _Z3barv
+    Type:            STT_FUNC
+    Section:         .text
+    Binding:         STB_GLOBAL
+    Value:           0x00000000000012EC
+    Size:            0x000000000000003C
+  - Name:            _Z3foov
+    Type:            STT_FUNC
+    Section:         .text
+    Binding:         STB_GLOBAL
+    Value:           0x00000000000012B0
+    Size:            0x000000000000003C
+  - Name:            _Z3jarv
+    Type:            STT_FUNC
+    Section:         .text
+    Binding:         STB_GLOBAL
+    Value:           0x0000000000001328
+    Size:            0x000000000000003C
+...
diff --git a/llvm/test/tools/llvm-xray/ARM/extract-instrmap.test b/llvm/test/tools/llvm-xray/ARM/extract-instrmap.test
new file mode 100644
--- /dev/null
+++ b/llvm/test/tools/llvm-xray/ARM/extract-instrmap.test
@@ -0,0 +1,25 @@
+## This test makes sure we can extract the instrumentation map from an
+## XRay-instrumented PIE file.
+
+# RUN: yaml2obj %S/Inputs/elf32-pic.yaml -o %t.so
+# RUN: llvm-xray extract %t.so -s | FileCheck %s
+
+# CHECK:      ---
+# CHECK-NEXT: - { id: 1, address: 0x00000000000012B0, function: 0x00000000000012B0, kind: function-enter, always-instrument: true, function-name: 'foo()' }
+# CHECK-NEXT: - { id: 1, address: 0x00000000000012CC, function: 0x00000000000012B0, kind: function-exit, always-instrument: true, function-name: 'foo()' }
+# CHECK-NEXT: - { id: 2, address: 0x00000000000012EC, function: 0x00000000000012EC, kind: function-enter, always-instrument: true, function-name: 'bar()' }
+# CHECK-NEXT: - { id: 2, address: 0x0000000000001308, function: 0x00000000000012EC, kind: function-exit, always-instrument: true, function-name: 'bar()' }
+# CHECK-NEXT: - { id: 3, address: 0x0000000000001328, function: 0x0000000000001328, kind: function-enter, always-instrument: true, function-name: 'jar()' }
+# CHECK-NEXT: - { id: 3, address: 0x0000000000001344, function: 0x0000000000001328, kind: function-exit, always-instrument: true, function-name: 'jar()' }
+# CHECK-NEXT: ...
+
+# RUN: llvm-xray extract -s --no-demangle %t.so | FileCheck --check-prefix=MANGLED %s
+
+# MANGLED:      ---
+# MANGLED-NEXT: - { id: 1, address: 0x00000000000012B0, function: 0x00000000000012B0, kind: function-enter, always-instrument: true, function-name: _Z3foov }
+# MANGLED-NEXT: - { id: 1, address: 0x00000000000012CC, function: 0x00000000000012B0, kind: function-exit, always-instrument: true, function-name: _Z3foov }
+# MANGLED-NEXT: - { id: 2, address: 0x00000000000012EC, function: 0x00000000000012EC, kind: function-enter, always-instrument: true, function-name: _Z3barv }
+# MANGLED-NEXT: - { id: 2, address: 0x0000000000001308, function: 0x00000000000012EC, kind: function-exit, always-instrument: true, function-name: _Z3barv }
+# MANGLED-NEXT: - { id: 3, address: 0x0000000000001328, function: 0x0000000000001328, kind: function-enter, always-instrument: true, function-name: _Z3jarv }
+# MANGLED-NEXT: - { id: 3, address: 0x0000000000001344, function: 0x0000000000001328, kind: function-exit, always-instrument: true, function-name: _Z3jarv }
+# MANGLED-NEXT: ...
diff --git a/llvm/test/tools/llvm-xray/X86/bad-instrmap-sizes.txt b/llvm/test/tools/llvm-xray/X86/bad-instrmap-sizes.txt
--- a/llvm/test/tools/llvm-xray/X86/bad-instrmap-sizes.txt
+++ b/llvm/test/tools/llvm-xray/X86/bad-instrmap-sizes.txt
@@ -1,3 +1,3 @@
 ; RUN: not llvm-xray extract %S/Inputs/elf64-badentrysizes.bin 2>&1 | FileCheck %s
 ; CHECK: llvm-xray: Cannot extract instrumentation map from '{{.*}}elf64-badentrysizes.bin'.
-; CHECK-NEXT: Instrumentation map entries not evenly divisible by size of an XRay sled entry in ELF64.
+; CHECK-NEXT: Instrumentation map entries not evenly divisible by size of an XRay sled entry.
diff --git a/llvm/test/tools/llvm-xray/X86/unsupported-elf32.txt b/llvm/test/tools/llvm-xray/X86/unsupported-elf32.txt
--- a/llvm/test/tools/llvm-xray/X86/unsupported-elf32.txt
+++ b/llvm/test/tools/llvm-xray/X86/unsupported-elf32.txt
@@ -1,3 +1,3 @@
 ; RUN: not llvm-xray extract %S/Inputs/elf32-noxray.bin 2>&1 | FileCheck %s
 ; CHECK: llvm-xray: Cannot extract instrumentation map from '{{.*}}elf32-noxray.bin'.
-; CHECK-NEXT: File format not supported (only does ELF and Mach-O little endian 64-bit).
+; CHECK-NEXT: File format not supported.  Supports: AArch64/ARM/ppc64le/x86-64.