diff --git a/folly/experimental/symbolizer/Dwarf.cpp b/folly/experimental/symbolizer/Dwarf.cpp
index aca081dafbe2f2b0ab4eceb3e47bbe7eeb70e695..42bf55269ca495fa312918833d7f25db7c13bac0 100644
--- a/folly/experimental/symbolizer/Dwarf.cpp
+++ b/folly/experimental/symbolizer/Dwarf.cpp
@@ -19,6 +19,7 @@
 #include <array>
 
 #include <dwarf.h>
+#include <folly/Optional.h>
 #include <type_traits>
 
 namespace folly {
@@ -76,10 +77,11 @@ struct Attribute {
   boost::variant<uint64_t, folly::StringPiece> attrValue;
 };
 
-struct CodeLocation {
-  Die die;
-  folly::Optional<uint64_t> file;
-  folly::Optional<uint64_t> line;
+// Indicates inline funtion `name` is called  at `line@file`.
+struct CallLocation {
+  Path file = {};
+  uint64_t line;
+  folly::StringPiece name;
 };
 
 } // namespace detail
@@ -468,18 +470,15 @@ bool Dwarf::findLocation(
 
   // Offset in .debug_line for the line number VM program for this
   // compilation unit
-  bool foundLineOffset = false;
-  uint64_t lineOffset = 0;
+  folly::Optional<uint64_t> lineOffset;
   folly::StringPiece compilationDirectory;
-  folly::StringPiece mainFileName;
-
+  folly::Optional<folly::StringPiece> mainFileName;
   forEachAttribute(cu, die, [&](const detail::Attribute& attr) {
     switch (attr.spec.name) {
       case DW_AT_stmt_list:
         // Offset in .debug_line for the line number VM program for this
         // compilation unit
         lineOffset = boost::get<uint64_t>(attr.attrValue);
-        foundLineOffset = true;
         break;
       case DW_AT_comp_dir:
         // Compilation directory
@@ -494,17 +493,17 @@ bool Dwarf::findLocation(
     return true;
   });
 
-  if (!mainFileName.empty()) {
+  if (mainFileName) {
     locationInfo.hasMainFile = true;
-    locationInfo.mainFile = Path(compilationDirectory, "", mainFileName);
+    locationInfo.mainFile = Path(compilationDirectory, "", *mainFileName);
   }
 
-  if (!foundLineOffset) {
+  if (!lineOffset) {
     return false;
   }
 
   folly::StringPiece lineSection(debugLine_);
-  lineSection.advance(lineOffset);
+  lineSection.advance(*lineOffset);
   LineNumberVM lineVM(lineSection, compilationDirectory);
 
   // Execute line number VM program to find file and line
@@ -518,75 +517,85 @@ bool Dwarf::findLocation(
     std::array<detail::DIEAbbreviation, kMaxAbbreviationEntries> abbrs;
     cu.abbrCache = folly::range(abbrs);
     readCompilationUnitAbbrs(debugAbbrev_, cu);
+
+    // Find the subprogram that matches the given address.
     detail::Die subprogram;
     findSubProgramDieForAddress(cu, die, address, subprogram);
+
     // Subprogram is the DIE of caller function.
     if (subprogram.abbr.hasChildren) {
-      size_t size = std::min<size_t>(
-          Dwarf::kMaxInlineLocationInfoPerFrame, inlineFrames.size());
-      detail::CodeLocation inlineLocs[size];
-      auto inlineLocsRange =
-          folly::Range<detail::CodeLocation*>(inlineLocs, size);
+      // Use an extra location and get its call file and call line, so that
+      // they can be used for the second last location when we don't have
+      // enough inline frames for all inline functions call stack.
+      size_t size =
+          std::min<size_t>(
+              Dwarf::kMaxInlineLocationInfoPerFrame, inlineFrames.size()) +
+          1;
+      detail::CallLocation callLocations[size];
+      size_t numFound = 0;
       findInlinedSubroutineDieForAddress(
-          cu, subprogram, address, inlineLocsRange);
-      size_t numFound = inlineLocsRange.data() - inlineLocs;
-
-      // The line in locationInfo is the line in the deepest inline functions,
-      // and the lines in inlineLocationInfo are the line of callers in call
-      // sequence. A shuffle is needed to match lines with their function name.
-      uint64_t callerLine = locationInfo.line;
-      inlineLocsRange =
-          folly::Range<detail::CodeLocation*>(inlineLocs, numFound);
-      // Put inline frames from inside to outside (callee is before caller).
-      std::reverse(inlineLocsRange.begin(), inlineLocsRange.end());
-      auto inlineFrameIter = inlineFrames.begin();
-      for (auto inlineLocIter = inlineLocsRange.begin();
-           inlineLocIter != inlineLocsRange.end();
-           inlineLocIter++, inlineFrameIter++) {
-        inlineFrameIter->location.line = callerLine;
-        if (!inlineLocIter->line) {
-          break;
+          cu,
+          subprogram,
+          lineVM,
+          address,
+          folly::Range<detail::CallLocation*>(callLocations, size),
+          numFound);
+
+      if (numFound > 0) {
+        folly::Range<detail::CallLocation*> inlineLocations(
+            callLocations, numFound);
+
+        const auto innerMostFile = locationInfo.file;
+        const auto innerMostLine = locationInfo.line;
+
+        // Earlier we filled in locationInfo:
+        // - mainFile: the path to the CU -- the file where the non-inlined
+        //   call is made from.
+        // - file + line: the location of the inner-most inlined call.
+        // Here we already find inlined info so mainFile would be redundant.
+        locationInfo.hasMainFile = false;
+        locationInfo.mainFile = Path{};
+        // @findInlinedSubroutineDieForAddress fills inlineLocations[0] with the
+        // file+line of the non-inlined outer function making the call.
+        // locationInfo.name is already set by the caller by looking up the
+        // non-inlined function @address belongs to.
+        locationInfo.hasFileAndLine = true;
+        locationInfo.file = inlineLocations[0].file;
+        locationInfo.line = inlineLocations[0].line;
+
+        // The next inlined subroutine's call file and call line is the current
+        // caller's location.
+        for (size_t i = 0; i < numFound - 1; i++) {
+          inlineLocations[i].file = inlineLocations[i + 1].file;
+          inlineLocations[i].line = inlineLocations[i + 1].line;
         }
-        callerLine = inlineLocIter->line.value();
-
-        folly::Optional<folly::StringPiece> linkageName;
-        folly::Optional<folly::StringPiece> name;
-        forEachAttribute(
-            cu, inlineLocIter->die, [&](const detail::Attribute& attr) {
-              switch (attr.spec.name) {
-                case DW_AT_linkage_name:
-                  linkageName = boost::get<folly::StringPiece>(attr.attrValue);
-                  break;
-                case DW_AT_name:
-                  name = boost::get<folly::StringPiece>(attr.attrValue);
-                  break;
-                case DW_AT_decl_file:
-                  // If the inline function is declared and defined in the same
-                  // file, the declaration subprogram may not have attribute
-                  // DW_AT_decl_file, then we need to find decl_file in the
-                  // definition subprogram.
-                  if (!inlineLocIter->file) {
-                    inlineLocIter->file = boost::get<uint64_t>(attr.attrValue);
-                  }
-                  break;
-              }
-              return !inlineLocIter->file || !name || !linkageName;
-            });
-        if (!(name || linkageName) || !inlineLocIter->file) {
-          break;
+        // CallLocation for the inner-most inlined function:
+        // - will be computed if enough space was available in the passed
+        //   buffer.
+        // - will have a .name, but no !.file && !.line
+        // - its corresponding file+line is the one returned by LineVM based
+        //   on @address.
+        // Use the inner-most inlined file+line info we got from the LineVM.
+        inlineLocations[numFound - 1].file = innerMostFile;
+        inlineLocations[numFound - 1].line = innerMostLine;
+
+        // Skip the extra location when actual inline function calls are more
+        // than provided frames.
+        inlineLocations = inlineLocations.subpiece(
+            0, std::min(numFound, inlineFrames.size()));
+
+        // Fill in inline frames in reverse order (as
+        // expected by the caller).
+        std::reverse(inlineLocations.begin(), inlineLocations.end());
+        for (size_t i = 0; i < inlineLocations.size(); i++) {
+          inlineFrames[i].found = true;
+          inlineFrames[i].addr = address;
+          inlineFrames[i].name = inlineLocations[i].name.data();
+          inlineFrames[i].location.hasFileAndLine = true;
+          inlineFrames[i].location.file = inlineLocations[i].file;
+          inlineFrames[i].location.line = inlineLocations[i].line;
         }
-
-        inlineFrameIter->found = true;
-        inlineFrameIter->addr = address;
-        inlineFrameIter->name =
-            linkageName ? linkageName.value().data() : name.value().data();
-        inlineFrameIter->location.hasFileAndLine = true;
-        inlineFrameIter->location.name =
-            linkageName ? linkageName.value() : name.value();
-        inlineFrameIter->location.file =
-            lineVM.getFullFileName(inlineLocIter->file.value());
       }
-      locationInfo.line = callerLine;
     }
   }
 
@@ -820,23 +829,34 @@ void Dwarf::findSubProgramDieForAddress(
   });
 }
 
+/**
+ * Find DW_TAG_inlined_subroutine child DIEs that contain @address and
+ * then extract:
+ * - Where was it called from (DW_AT_call_file & DW_AT_call_line):
+ *   the statement or expression that caused the inline expansion.
+ * - The inlined function's name. As a function may be inlined multiple
+ *   times, common attributes like DW_AT_linkage_name or DW_AT_name
+ *   are only stored in its "concrete out-of-line instance" (a
+ *   DW_TAG_subprogram) which we find using DW_AT_abstract_origin.
+ */
 void Dwarf::findInlinedSubroutineDieForAddress(
     const detail::CompilationUnit& cu,
     const detail::Die& die,
+    const LineNumberVM& lineVM,
     uint64_t address,
-    folly::Range<detail::CodeLocation*>& isrLoc) const {
-  if (isrLoc.empty()) {
+    folly::Range<detail::CallLocation*> locations,
+    size_t& numFound) const {
+  if (numFound >= locations.size()) {
     return;
   }
+
   forEachChild(cu, die, [&](const detail::Die& childDie) {
-    if (childDie.abbr.tag != DW_TAG_inlined_subroutine) {
-      return true; // Skip DIE that is not inlined_subroutine.
-    }
     folly::Optional<uint64_t> lowPc;
     folly::Optional<uint64_t> highPc;
     folly::Optional<bool> isHighPcAddr;
-    folly::Optional<uint64_t> origin;
-    folly::Optional<uint64_t> originRefType;
+    folly::Optional<uint64_t> abstractOrigin;
+    folly::Optional<uint64_t> abstractOriginRefType;
+    folly::Optional<uint64_t> callFile;
     folly::Optional<uint64_t> callLine;
     folly::Optional<uint64_t> rangeOffset;
     forEachAttribute(cu, childDie, [&](const detail::Attribute& attr) {
@@ -854,59 +874,115 @@ void Dwarf::findInlinedSubroutineDieForAddress(
           highPc = boost::get<uint64_t>(attr.attrValue);
           break;
         case DW_AT_abstract_origin:
-          originRefType = attr.spec.form;
-          origin = boost::get<uint64_t>(attr.attrValue);
+          abstractOriginRefType = attr.spec.form;
+          abstractOrigin = boost::get<uint64_t>(attr.attrValue);
           break;
         case DW_AT_call_line:
           callLine = boost::get<uint64_t>(attr.attrValue);
           break;
+        case DW_AT_call_file:
+          callFile = boost::get<uint64_t>(attr.attrValue);
+          break;
       }
       // Iterate through all until find all above attributes.
       return true;
     });
-    if (!origin || !originRefType || !callLine) {
-      // Missing required fields. Keep searching other children.
-      return true;
-    }
-    if ((!lowPc || !highPc || !isHighPcAddr || address < *lowPc ||
-         address >= (*isHighPcAddr ? *highPc : *lowPc + *highPc)) &&
-        (!rangeOffset ||
-         !isAddrInRangeList(address, rangeOffset.value(), cu.addrSize))) {
+
+    // 2.17 Code Addresses and Ranges
+    // Any debugging information entry describing an entity that has a
+    // machine code address or range of machine code addresses,
+    // which includes compilation units, module initialization, subroutines,
+    // ordinary blocks, try/catch blocks, labels and the like, may have
+    //  - A DW_AT_low_pc attribute for a single address,
+    //  - A DW_AT_low_pc and DW_AT_high_pc pair of attributes for a
+    //    single contiguous range of addresses, or
+    //  - A DW_AT_ranges attribute for a non-contiguous range of addresses.
+    // TODO: Support DW_TAG_entry_point and DW_TAG_common_block that don't
+    // have DW_AT_low_pc/DW_AT_high_pc pairs and DW_AT_ranges.
+    bool pcMatch = lowPc && highPc && isHighPcAddr && address >= *lowPc &&
+        (address < (*isHighPcAddr ? *highPc : *lowPc + *highPc));
+    bool rangeMatch = rangeOffset &&
+        isAddrInRangeList(address, rangeOffset.value(), cu.addrSize);
+    if (!pcMatch && !rangeMatch) {
       // Address doesn't match. Keep searching other children.
       return true;
     }
 
-    isrLoc[0].line = *callLine;
-    auto setLocationInfo = [&](const detail::CompilationUnit& srcu,
+    // Between a DW_TAG_subprogram and and DW_TAG_inlined_subroutine we might
+    // have arbitrary intermediary "nodes", including DW_TAG_common_block,
+    // DW_TAG_lexical_block, DW_TAG_try_block, DW_TAG_catch_block and
+    // DW_TAG_with_stmt, etc.
+    if (childDie.abbr.tag == DW_TAG_try_block ||
+        childDie.abbr.tag == DW_TAG_catch_block ||
+        childDie.abbr.tag == DW_TAG_entry_point ||
+        childDie.abbr.tag == DW_TAG_common_block ||
+        childDie.abbr.tag == DW_TAG_lexical_block) {
+      findInlinedSubroutineDieForAddress(
+          cu, childDie, lineVM, address, locations, numFound);
+      // We expect a single sibling DIE to match on addr. Stop searching for
+      // other DIEs.
+      return false;
+    }
+
+    if (!abstractOrigin || !abstractOriginRefType || !callLine || !callFile) {
+      // We expect a single sibling DIE to match on addr, but it's missing
+      // required fields. Stop searching for other DIEs.
+      return false;
+    }
+
+    locations[numFound].file = lineVM.getFullFileName(*callFile);
+    locations[numFound].line = *callLine;
+
+    auto getFunctionName = [&](const detail::CompilationUnit& srcu,
                                uint64_t dieOffset) {
       auto declDie = getDieAtOffset(srcu, dieOffset);
-      // If the inline function is declared and defined in different file, then
-      // DW_AT_decl_file attribute of the declaration may contain the definition
-      // file name.
-      isrLoc[0].file = getAttribute<uint64_t>(srcu, declDie, DW_AT_decl_file);
       // Jump to the actual function definition instead of declaration for name
       // and line info.
-      isrLoc[0].die = findDefinitionDie(srcu, declDie);
-      isrLoc.advance(1);
+      auto defDie = findDefinitionDie(srcu, declDie);
+
+      folly::StringPiece name;
+      // The file and line will be set in the next inline subroutine based on
+      // its DW_AT_call_file and DW_AT_call_line.
+      forEachAttribute(srcu, defDie, [&](const detail::Attribute& attr) {
+        switch (attr.spec.name) {
+          case DW_AT_linkage_name:
+            name = boost::get<folly::StringPiece>(attr.attrValue);
+            break;
+          case DW_AT_name:
+            // NOTE: when DW_AT_linkage_name and DW_AT_name match, dwarf
+            // emitters omit DW_AT_linkage_name (to save space). If present
+            // DW_AT_linkage_name should always be preferred (mangled C++ name
+            // vs just the function name).
+            if (name.empty()) {
+              name = boost::get<folly::StringPiece>(attr.attrValue);
+            }
+            break;
+        }
+        return true;
+      });
+      return name;
     };
-    if (*originRefType == DW_FORM_ref1 || *originRefType == DW_FORM_ref2 ||
-        *originRefType == DW_FORM_ref4 || *originRefType == DW_FORM_ref8 ||
-        *originRefType == DW_FORM_ref_udata) {
-      // These reference types identify any debugging information entry within
-      // the containing unit. This type of reference is an offset from the first
-      // byte of the compilation header for the compilation unit containing the
-      // reference.
-      setLocationInfo(cu, cu.offset + *origin);
-      findInlinedSubroutineDieForAddress(cu, childDie, address, isrLoc);
-    } else if (*originRefType == DW_FORM_ref_addr) {
-      // DW_FORM_ref_addr identifies any debugging information entry
-      // within a .debug_info section; in particular, it may refer to an entry
-      // in a different compilation unit from the unit containing the reference,
-      // and may refer to an entry in a different shared object.
-      auto srcu = findCompilationUnit(debugInfo_, *origin);
-      setLocationInfo(srcu, *origin);
-      findInlinedSubroutineDieForAddress(srcu, childDie, address, isrLoc);
-    }
+
+    // DW_AT_abstract_origin is a reference. There a 3 types of references:
+    // - the reference can identify any debugging information entry within the
+    //   compilation unit (DW_FORM_ref1, DW_FORM_ref2, DW_FORM_ref4,
+    //   DW_FORM_ref8, DW_FORM_ref_udata). This type of reference is an offset
+    //   from the first byte of the compilation header for the compilation unit
+    //   containing the reference.
+    // - the reference can identify any debugging information entry within a
+    //   .debug_info section; in particular, it may refer to an entry in a
+    //   different compilation unit (DW_FORM_ref_addr)
+    // - the reference can identify any debugging information type entry that
+    //   has been placed in its own type unit.
+    //   Not applicable for DW_AT_abstract_origin.
+    locations[numFound].name = (*abstractOriginRefType != DW_FORM_ref_addr)
+        ? getFunctionName(cu, cu.offset + *abstractOrigin)
+        : getFunctionName(
+              findCompilationUnit(debugInfo_, *abstractOrigin),
+              *abstractOrigin);
+
+    findInlinedSubroutineDieForAddress(
+        cu, childDie, lineVM, address, locations, ++numFound);
 
     return false;
   });
diff --git a/folly/experimental/symbolizer/Dwarf.h b/folly/experimental/symbolizer/Dwarf.h
index 5ba4263027cb07323503d59dd64b2d4fc51c7dae..70eaa51861c68eb6f8a13116b3e112229f9cfffd 100644
--- a/folly/experimental/symbolizer/Dwarf.h
+++ b/folly/experimental/symbolizer/Dwarf.h
@@ -44,7 +44,7 @@ struct DIEAbbreviation;
 
 struct AttributeSpec;
 struct Attribute;
-struct CodeLocation;
+struct CallLocation;
 
 } // namespace detail
 
@@ -85,7 +85,7 @@ class Dwarf {
    * More than one location info may exist if current frame is an inline
    * function call.
    */
-  static const uint32_t kMaxInlineLocationInfoPerFrame = 3;
+  static const uint32_t kMaxInlineLocationInfoPerFrame = 10;
 
   /** Find the file and line number information corresponding to address. */
   bool findAddress(
@@ -136,8 +136,10 @@ class Dwarf {
   void findInlinedSubroutineDieForAddress(
       const detail::CompilationUnit& cu,
       const detail::Die& die,
+      const LineNumberVM& lineVM,
       uint64_t address,
-      folly::Range<detail::CodeLocation*>& isrLoc) const;
+      folly::Range<detail::CallLocation*> locations,
+      size_t& numFound) const;
 
   static bool
   findDebugInfoOffset(uintptr_t address, StringPiece aranges, uint64_t& offset);
diff --git a/folly/experimental/symbolizer/test/DwarfBenchmark.cpp b/folly/experimental/symbolizer/test/DwarfBenchmark.cpp
index 7a4bc915dfb306f4b19df67fd7dde9dcae35cf24..3cb6687078faca135fcf6b4ba3e7cb3b3964a6ee 100644
--- a/folly/experimental/symbolizer/test/DwarfBenchmark.cpp
+++ b/folly/experimental/symbolizer/test/DwarfBenchmark.cpp
@@ -18,27 +18,40 @@
 #include <folly/Range.h>
 #include <folly/experimental/symbolizer/Dwarf.h>
 #include <folly/experimental/symbolizer/SymbolizedFrame.h>
+#include <folly/experimental/symbolizer/test/SymbolizerTestUtils.h>
 #include <folly/portability/GFlags.h>
 
-void dummy() {}
-
 namespace {
 
 using namespace folly::symbolizer;
+using namespace folly::symbolizer::test;
+
+template <size_t kNumFrames>
+FOLLY_NOINLINE void lexicalBlockBar(FrameArray<kNumFrames>& frames) try {
+  size_t unused = 0;
+  unused++;
+  inlineBar(frames);
+} catch (...) {
+  folly::assume_unreachable();
+}
 
 void run(LocationInfoMode mode, size_t n) {
   folly::BenchmarkSuspender suspender;
-  // NOTE: Using '/proc/self/exe' only works if the code for @dummy is
-  // statically linked into the binary.
+  Symbolizer symbolizer(nullptr, LocationInfoMode::FULL_WITH_INLINE, 0);
+  FrameArray<100> frames;
+  lexicalBlockBar<100>(frames);
+  symbolizer.symbolize(frames);
+  // The address of the line where lexicalBlockBar calls inlineBar.
+  uintptr_t address = frames.frames[7].addr;
+
   ElfFile elf("/proc/self/exe");
   Dwarf dwarf(&elf);
+  auto inlineFrames = std::array<SymbolizedFrame, 10>();
   suspender.dismiss();
+
   for (size_t i = 0; i < n; i++) {
     LocationInfo info;
-    auto inlineFrames =
-        std::array<SymbolizedFrame, Dwarf::kMaxInlineLocationInfoPerFrame>();
-    dwarf.findAddress(
-        uintptr_t(&dummy), mode, info, folly::range(inlineFrames));
+    dwarf.findAddress(address, mode, info, folly::range(inlineFrames));
   }
 }
 
diff --git a/folly/experimental/symbolizer/test/SymbolizerTest.cpp b/folly/experimental/symbolizer/test/SymbolizerTest.cpp
index 79e6773e0b0a288d333ba74c357f66e28f2e68dc..ad6adfa7ad7a123180121d682c24a4abde49fbaa 100644
--- a/folly/experimental/symbolizer/test/SymbolizerTest.cpp
+++ b/folly/experimental/symbolizer/test/SymbolizerTest.cpp
@@ -123,10 +123,14 @@ TEST(SymbolizerTest, SymbolCache) {
 
 namespace {
 
-template <size_t kNumFrames = 100>
-FOLLY_ALWAYS_INLINE void inlineBar(FrameArray<kNumFrames>& frames) {
-  kFooCallByStandaloneBarLineNo = __LINE__ + 1;
-  inlineFoo(frames);
+template <size_t kNumFrames>
+FOLLY_NOINLINE void lexicalBlockBar(FrameArray<kNumFrames>& frames) try {
+  size_t unused = 0;
+  unused++;
+  kInlineBarCallByLexicalBarLineNo = __LINE__ + 1;
+  inlineBar(frames);
+} catch (...) {
+  folly::assume_unreachable();
 }
 
 void verifyStackTrace(
@@ -139,7 +143,7 @@ void verifyStackTrace(
       "folly::symbolizer::FrameArray<100ul>&)",
       std::string(folly::demangle(frames.frames[5].name)));
   EXPECT_EQ(
-      "folly/experimental/symbolizer/test/SymbolizerTestUtils-inl.h",
+      "./folly/experimental/symbolizer/test/SymbolizerTestUtils-inl.h",
       std::string(frames.frames[5].location.file.toString()));
   EXPECT_EQ(kQsortCallLineNo, frames.frames[5].location.line);
   EXPECT_EQ(barName, std::string(folly::demangle(frames.frames[6].name)));
@@ -205,10 +209,10 @@ TEST(SymbolizerTest, InlineFunctionBasic) {
   // clang-format on
   verifyStackTrace(
       frames,
-      "void folly::symbolizer::test::(anonymous namespace)::inlineBar<100ul>("
+      "void folly::symbolizer::test::inlineBar<100ul>("
       "folly::symbolizer::FrameArray<100ul>&)",
       kFooCallByStandaloneBarLineNo,
-      "folly/experimental/symbolizer/test/SymbolizerTest.cpp");
+      "folly/experimental/symbolizer/test/SymbolizerTestUtils-inl.h");
 
   FrameArray<100> frames2;
   inlineBar<100>(frames2);
@@ -217,6 +221,80 @@ TEST(SymbolizerTest, InlineFunctionBasic) {
   compareFrames(frames, frames2);
 }
 
+TEST(SymbolizerTest, InlineFunctionWithoutEnoughFrames) {
+  Symbolizer symbolizer(nullptr, LocationInfoMode::FULL_WITH_INLINE, 0);
+
+  FrameArray<100> frames;
+  lexicalBlockBar<100>(frames);
+  symbolizer.symbolize(frames);
+
+  // The address of the line where lexicalBlockBar calls inlineBar.
+  uintptr_t address = frames.frames[7].addr;
+  std::array<SymbolizedFrame, 2> limitedFrames;
+  symbolizer.symbolize(
+      folly::Range<const uintptr_t*>(&address, 1), folly::range(limitedFrames));
+
+  EXPECT_EQ(
+      "void folly::symbolizer::test::inlineBar<100ul>("
+      "folly::symbolizer::FrameArray<100ul>&)",
+      std::string(folly::demangle(limitedFrames[0].name)));
+  EXPECT_EQ(
+      "folly/experimental/symbolizer/test/SymbolizerTestUtils-inl.h",
+      std::string(limitedFrames[0].location.file.toString()));
+  EXPECT_EQ(kFooCallByStandaloneBarLineNo, limitedFrames[0].location.line);
+
+  EXPECT_EQ(
+      "void folly::symbolizer::test::(anonymous namespace)::lexicalBlockBar"
+      "<100ul>(folly::symbolizer::FrameArray<100ul>&)",
+      std::string(folly::demangle(limitedFrames[1].name)));
+  EXPECT_EQ(
+      "folly/experimental/symbolizer/test/SymbolizerTest.cpp",
+      std::string(limitedFrames[1].location.file.toString()));
+  EXPECT_EQ(kInlineBarCallByLexicalBarLineNo, limitedFrames[1].location.line);
+}
+
+TEST(SymbolizerTest, InlineFunctionInLexicalBlock) {
+  Symbolizer symbolizer(nullptr, LocationInfoMode::FULL_WITH_INLINE, 0);
+
+  FrameArray<100> frames;
+  lexicalBlockBar<100>(frames);
+  symbolizer.symbolize(frames);
+
+  verifyStackTrace(
+      frames,
+      "void folly::symbolizer::test::inlineBar<100ul>("
+      "folly::symbolizer::FrameArray<100ul>&)",
+      kFooCallByStandaloneBarLineNo,
+      "folly/experimental/symbolizer/test/SymbolizerTestUtils-inl.h");
+
+  EXPECT_EQ(
+      "void folly::symbolizer::test::(anonymous namespace)::lexicalBlockBar"
+      "<100ul>(folly::symbolizer::FrameArray<100ul>&)",
+      std::string(folly::demangle(frames.frames[7].name)));
+  EXPECT_EQ(
+      "folly/experimental/symbolizer/test/SymbolizerTest.cpp",
+      std::string(frames.frames[7].location.file.toString()));
+  EXPECT_EQ(kInlineBarCallByLexicalBarLineNo, frames.frames[7].location.line);
+}
+
+TEST(SymbolizerTest, InlineFunctionInDifferentCompilationUnit) {
+  Symbolizer symbolizer(nullptr, LocationInfoMode::FULL_WITH_INLINE, 0);
+
+  FrameArray<100> frames;
+  // NOTE: inlineBaz is only inlined with thinlto compilation mode enabled.
+  inlineBaz(frames);
+  symbolizer.symbolize(frames);
+
+  EXPECT_EQ(
+      "folly::symbolizer::test::inlineBaz("
+      "folly::symbolizer::FrameArray<100ul>&)",
+      std::string(folly::demangle(frames.frames[6].name)));
+  EXPECT_EQ(
+      "folly/experimental/symbolizer/test/SymbolizerTestUtils.cpp",
+      std::string(frames.frames[6].location.file.toString()));
+  EXPECT_EQ(kFooCallByStandaloneBazLineNo, frames.frames[6].location.line);
+}
+
 TEST(SymbolizerTest, InlineClassMemberFunction) {
   Symbolizer symbolizer(nullptr, LocationInfoMode::FULL_WITH_INLINE, 0);
 
@@ -303,10 +381,10 @@ TEST(SymbolizerTest, InlineFunctionWithCache) {
 
   verifyStackTrace(
       frames,
-      "void folly::symbolizer::test::(anonymous namespace)::inlineBar<100ul>("
+      "void folly::symbolizer::test::inlineBar<100ul>("
       "folly::symbolizer::FrameArray<100ul>&)",
       kFooCallByStandaloneBarLineNo,
-      "folly/experimental/symbolizer/test/SymbolizerTest.cpp");
+      "folly/experimental/symbolizer/test/SymbolizerTestUtils-inl.h");
 
   FrameArray<100> frames2;
   inlineBar<100>(frames2);
diff --git a/folly/experimental/symbolizer/test/SymbolizerTestUtils-inl.h b/folly/experimental/symbolizer/test/SymbolizerTestUtils-inl.h
index 9d31431e21a9ea0e3e6be8c2e60581adcdd27300..2b40a6e951cfb635762491b91bd6dd6ad6bac680 100644
--- a/folly/experimental/symbolizer/test/SymbolizerTestUtils-inl.h
+++ b/folly/experimental/symbolizer/test/SymbolizerTestUtils-inl.h
@@ -35,6 +35,12 @@ FOLLY_ALWAYS_INLINE void inlineFoo(FrameArray<kNumFrames>& frames) {
   framesToFill = nullptr;
 }
 
+template <size_t kNumFrames>
+FOLLY_ALWAYS_INLINE void inlineBar(FrameArray<kNumFrames>& frames) {
+  kFooCallByStandaloneBarLineNo = __LINE__ + 1;
+  inlineFoo(frames);
+}
+
 FOLLY_ALWAYS_INLINE void InlineFunctionsWrapper::inlineBar(
     FrameArray<100>& frames) const {
   kFooCallByClassInDifferentFileBarLineNo = __LINE__ + 1;
diff --git a/folly/experimental/symbolizer/test/SymbolizerTestUtils.cpp b/folly/experimental/symbolizer/test/SymbolizerTestUtils.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f45ef173bf1e151d36fd9d3b5db40db9c15c4f16
--- /dev/null
+++ b/folly/experimental/symbolizer/test/SymbolizerTestUtils.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <folly/experimental/symbolizer/test/SymbolizerTestUtils.h>
+
+namespace folly {
+namespace symbolizer {
+namespace test {
+
+void* framesToFill = {nullptr};
+
+size_t kQsortCallLineNo = 0;
+size_t kFooCallByStandaloneBarLineNo = 0;
+size_t kFooCallByStandaloneBazLineNo = 0;
+size_t kFooCallByClassBarLineNo = 0;
+size_t kFooCallByClassStaticBarLineNo = 0;
+size_t kFooCallByClassInDifferentFileBarLineNo = 0;
+size_t kFooCallByClassInDifferentFileStaticBarLineNo = 0;
+size_t kInlineBarCallByLexicalBarLineNo = 0;
+size_t kInlineBazCallByLexicalBazLineNo = 0;
+
+void inlineBaz(FrameArray<100>& frames) {
+  kFooCallByStandaloneBazLineNo = __LINE__ + 1;
+  inlineFoo(frames);
+}
+
+} // namespace test
+} // namespace symbolizer
+} // namespace folly
diff --git a/folly/experimental/symbolizer/test/SymbolizerTestUtils.h b/folly/experimental/symbolizer/test/SymbolizerTestUtils.h
index 5d7489cd1a22f3a914c7dd913df52de9f9c51c78..7a9e857a5ff7d4951c6106f52d9d5612d3885203 100644
--- a/folly/experimental/symbolizer/test/SymbolizerTestUtils.h
+++ b/folly/experimental/symbolizer/test/SymbolizerTestUtils.h
@@ -23,7 +23,7 @@ namespace folly {
 namespace symbolizer {
 namespace test {
 
-void* framesToFill{nullptr};
+extern void* framesToFill;
 
 template <size_t kNumFrames = 100>
 int comparator(const void* ap, const void* bp) {
@@ -34,16 +34,23 @@ int comparator(const void* ap, const void* bp) {
   return a < b ? -1 : a > b ? 1 : 0;
 }
 
-size_t kQsortCallLineNo = 0;
-size_t kFooCallByStandaloneBarLineNo = 0;
-size_t kFooCallByClassBarLineNo = 0;
-size_t kFooCallByClassStaticBarLineNo = 0;
-size_t kFooCallByClassInDifferentFileBarLineNo = 0;
-size_t kFooCallByClassInDifferentFileStaticBarLineNo = 0;
+extern size_t kQsortCallLineNo;
+extern size_t kFooCallByStandaloneBarLineNo;
+extern size_t kFooCallByStandaloneBazLineNo;
+extern size_t kFooCallByClassBarLineNo;
+extern size_t kFooCallByClassStaticBarLineNo;
+extern size_t kFooCallByClassInDifferentFileBarLineNo;
+extern size_t kFooCallByClassInDifferentFileStaticBarLineNo;
+extern size_t kInlineBarCallByLexicalBarLineNo;
 
 template <size_t kNumFrames = 100>
 FOLLY_ALWAYS_INLINE void inlineFoo(FrameArray<kNumFrames>& frames);
 
+template <size_t kNumFrames = 100>
+FOLLY_ALWAYS_INLINE void inlineBar(FrameArray<kNumFrames>& frames);
+
+extern void inlineBaz(FrameArray<100>& frames);
+
 class InlineFunctionsWrapper {
  public:
   FOLLY_ALWAYS_INLINE void inlineBar(FrameArray<100>& frames) const;