@@ -92,28 +92,30 @@ StatusOr<std::unique_ptr<DwarfReader>> DwarfReader::CreateWithoutIndexing(
9292 auto dwarf_reader = std::unique_ptr<DwarfReader>(
9393 new DwarfReader (std::move (buffer), DWARFContext::create (*obj_file)));
9494
95- PX_RETURN_IF_ERROR (dwarf_reader->DetectSourceLanguage ());
96-
9795 return dwarf_reader;
9896}
9997
10098StatusOr<std::unique_ptr<DwarfReader>> DwarfReader::CreateIndexingAll (
10199 const std::filesystem::path& path) {
102100 PX_ASSIGN_OR_RETURN (auto dwarf_reader, CreateWithoutIndexing (path));
103101 dwarf_reader->IndexDIEs (std::nullopt );
102+ PX_RETURN_IF_ERROR (dwarf_reader->DetectSourceLanguage ());
104103 return dwarf_reader;
105104}
106105
107106StatusOr<std::unique_ptr<DwarfReader>> DwarfReader::CreateWithSelectiveIndexing (
108107 const std::filesystem::path& path, const std::vector<SymbolSearchPattern>& symbol_patterns) {
109108 PX_ASSIGN_OR_RETURN (auto dwarf_reader, CreateWithoutIndexing (path));
110109 dwarf_reader->IndexDIEs (symbol_patterns);
110+ PX_RETURN_IF_ERROR (dwarf_reader->DetectSourceLanguage ());
111111 return dwarf_reader;
112112}
113113
114114DwarfReader::DwarfReader (std::unique_ptr<llvm::MemoryBuffer> buffer,
115115 std::unique_ptr<llvm::DWARFContext> dwarf_context)
116- : memory_buffer_(std::move(buffer)), dwarf_context_(std::move(dwarf_context)) {
116+ : is_multi_lang_(std::nullopt ),
117+ memory_buffer_ (std::move(buffer)),
118+ dwarf_context_(std::move(dwarf_context)) {
117119 // Only very first call will actually perform initialization.
118120 InitLLVMOnce ();
119121}
@@ -154,31 +156,60 @@ bool IsNamespace(llvm::dwarf::Tag tag) { return tag == llvm::dwarf::DW_TAG_names
154156
155157} // namespace
156158
159+ StatusOr<std::pair<llvm::dwarf::SourceLanguage, std::string>>
160+ DwarfReader::DetectSourceLanguageFromCUDIE (const llvm::DWARFDie& unit_die) {
161+ if (unit_die.getTag () != llvm::dwarf::DW_TAG_compile_unit) {
162+ // Skip over DW_TAG_partial_unit, and potentially other tags.
163+ return error::NotFound (" Expected DW_TAG_compile_unit, but got DW_TAG=$0 for unit DIE: $1" ,
164+ magic_enum::enum_name (unit_die.getTag ()), Dump (unit_die));
165+ }
166+ const DWARFFormValue& producer_attr =
167+ GetAttribute (unit_die, llvm::dwarf::DW_AT_producer).ValueOr ({});
168+ auto s = producer_attr.getAsCString ();
169+ std::string compiler;
170+ #if LLVM_VERSION_MAJOR >= 14
171+ if (!s.takeError ()) {
172+ compiler = s.get ();
173+ }
174+ #else
175+ compiler = s.getValueOr (" " );
176+ #endif
177+ PX_ASSIGN_OR_RETURN (const DWARFFormValue& lang_attr,
178+ GetAttribute (unit_die, llvm::dwarf::DW_AT_language));
179+ auto source_language =
180+ static_cast <llvm::dwarf::SourceLanguage>(lang_attr.getAsUnsignedConstant ().getValue ());
181+ return std::make_pair (source_language, compiler);
182+ }
183+
157184Status DwarfReader::DetectSourceLanguage () {
185+ is_multi_lang_ = false ;
186+ std::optional<llvm::dwarf::SourceLanguage> prev_source_language;
187+ std::optional<std::string> prev_compiler;
158188 for (size_t i = 0 ; i < dwarf_context_->getNumCompileUnits (); ++i) {
159189 const auto & unit_die = dwarf_context_->getUnitAtIndex (i)->getUnitDIE ();
160- if (unit_die. getTag () != llvm::dwarf::DW_TAG_compile_unit) {
161- // Skip over DW_TAG_partial_unit, and potentially other tags.
190+ auto lang_s = DetectSourceLanguageFromCUDIE (unit_die);
191+ if (!lang_s. ok ()) {
162192 continue ;
163193 }
164-
165- PX_ASSIGN_OR (const DWARFFormValue& lang_attr,
166- GetAttribute (unit_die, llvm::dwarf::DW_AT_language), continue );
167- source_language_ =
168- static_cast <llvm::dwarf::SourceLanguage>(lang_attr.getAsUnsignedConstant ().getValue ());
169-
170- const DWARFFormValue& producer_attr =
171- GetAttribute (unit_die, llvm::dwarf::DW_AT_producer).ValueOr ({});
172-
173- auto s = producer_attr.getAsCString ();
174- #if LLVM_VERSION_MAJOR >= 14
175- if (!s.takeError ()) {
176- compiler_ = s.get ();
194+ auto p = lang_s.ValueOrDie ();
195+ auto source_language = p.first ;
196+ auto & compiler = p.second ;
197+
198+ if (!prev_source_language.has_value ()) {
199+ prev_source_language = source_language;
200+ } else if (prev_source_language.has_value () &&
201+ prev_source_language.value () != source_language) {
202+ is_multi_lang_ = true ;
177203 }
178- #else
179- compiler_ = s.getValueOr (" " );
180- #endif
181204
205+ if (!prev_compiler.has_value ()) {
206+ prev_compiler = compiler;
207+ } else if (prev_compiler.has_value () && prev_compiler.value () != compiler) {
208+ is_multi_lang_ = true ;
209+ }
210+ }
211+ if (prev_source_language.has_value () && prev_compiler.has_value ()) {
212+ source_language_ = prev_source_language.value ();
182213 return Status::OK ();
183214 }
184215 return error::Internal (
@@ -923,16 +954,20 @@ StatusOr<std::map<std::string, ArgInfo>> DwarfReader::GetFunctionArgInfo(
923954 // but DW_AT_location has been found to be blank in some cases, making it unreliable.
924955 // Instead, we use a FunctionArgTracker that tries to reverse engineer the calling convention.
925956
926- ABI abi = LanguageToABI (source_language_, compiler_);
957+ PX_ASSIGN_OR_RETURN (const DWARFDie& function_die,
958+ GetMatchingDIE (function_symbol_name, llvm::dwarf::DW_TAG_subprogram));
959+ // Certain binaries can have DW_TAG_compile_units with different source languages. When compiling
960+ // programs with ASAN/TSAN enabled this is common.
961+ llvm::DWARFUnit* cu = function_die.getDwarfUnit ();
962+ llvm::DWARFDie unit_die = cu->getUnitDIE ();
963+ PX_ASSIGN_OR_RETURN (auto p, DetectSourceLanguageFromCUDIE (unit_die));
964+ ABI abi = LanguageToABI (p.first , p.second );
927965 if (abi == ABI::kUnknown ) {
928966 return error::Unimplemented (" Unable to determine ABI from language: $0" ,
929967 magic_enum::enum_name (source_language_));
930968 }
931969 std::unique_ptr<ABICallingConventionModel> arg_tracker = ABICallingConventionModel::Create (abi);
932970
933- PX_ASSIGN_OR_RETURN (const DWARFDie& function_die,
934- GetMatchingDIE (function_symbol_name, llvm::dwarf::DW_TAG_subprogram));
935-
936971 // If function has a return value, process that first.
937972 // This is important, because in some ABIs (e.g. SystemV ABI),
938973 // if the return value is not able to be passed back in the available registers,
@@ -968,7 +1003,7 @@ StatusOr<std::map<std::string, ArgInfo>> DwarfReader::GetFunctionArgInfo(
9681003 PX_ASSIGN_OR_RETURN (const DWARFDie type_die, GetTypeDie (die));
9691004 PX_ASSIGN_OR_RETURN (arg.type_info , GetTypeInfo (die, type_die));
9701005
971- if (source_language_ == llvm::dwarf::DW_LANG_Go) {
1006+ if (p. first == llvm::dwarf::DW_LANG_Go) {
9721007 arg.retarg = IsGolangRetArg (die).ValueOr (false );
9731008 }
9741009
0 commit comments