forked from OSchip/llvm-project
[lldb] Add setting to override PE/COFF ABI by module name
The setting `plugin.object-file.pe-coff.module-abi` is a string-to-enum map that allows specifying an ABI to a module name. For example: ucrtbase.dll=msvc libstdc++-6.dll=gnu This allows for debugging a process which mixes both modules built using the MSVC ABI and modules built using the MinGW ABI. Depends on D127048 Reviewed By: DavidSpickett Differential Revision: https://reviews.llvm.org/D127234
This commit is contained in:
parent
4d12378395
commit
3c867898c7
|
@ -12,6 +12,7 @@
|
|||
#include <map>
|
||||
|
||||
#include "lldb/Interpreter/OptionValue.h"
|
||||
#include "lldb/lldb-private-types.h"
|
||||
|
||||
namespace lldb_private {
|
||||
|
||||
|
@ -19,8 +20,10 @@ class OptionValueDictionary
|
|||
: public Cloneable<OptionValueDictionary, OptionValue> {
|
||||
public:
|
||||
OptionValueDictionary(uint32_t type_mask = UINT32_MAX,
|
||||
OptionEnumValues enum_values = OptionEnumValues(),
|
||||
bool raw_value_dump = true)
|
||||
: m_type_mask(type_mask), m_raw_value_dump(raw_value_dump) {}
|
||||
: m_type_mask(type_mask), m_enum_values(enum_values),
|
||||
m_raw_value_dump(raw_value_dump) {}
|
||||
|
||||
~OptionValueDictionary() override = default;
|
||||
|
||||
|
@ -75,6 +78,7 @@ public:
|
|||
protected:
|
||||
typedef std::map<ConstString, lldb::OptionValueSP> collection;
|
||||
uint32_t m_type_mask;
|
||||
OptionEnumValues m_enum_values;
|
||||
collection m_values;
|
||||
bool m_raw_value_dump;
|
||||
};
|
||||
|
|
|
@ -8,11 +8,12 @@
|
|||
|
||||
#include "lldb/Interpreter/OptionValueDictionary.h"
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "lldb/DataFormatters/FormatManager.h"
|
||||
#include "lldb/Interpreter/OptionValueEnumeration.h"
|
||||
#include "lldb/Interpreter/OptionValueString.h"
|
||||
#include "lldb/Utility/Args.h"
|
||||
#include "lldb/Utility/State.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
|
@ -161,16 +162,26 @@ Status OptionValueDictionary::SetArgs(const Args &args,
|
|||
return error;
|
||||
}
|
||||
|
||||
lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask(
|
||||
value.str().c_str(), m_type_mask, error));
|
||||
if (value_sp) {
|
||||
if (m_type_mask == 1u << eTypeEnum) {
|
||||
auto enum_value =
|
||||
std::make_shared<OptionValueEnumeration>(m_enum_values, 0);
|
||||
error = enum_value->SetValueFromString(value);
|
||||
if (error.Fail())
|
||||
return error;
|
||||
m_value_was_set = true;
|
||||
SetValueForKey(ConstString(key), value_sp, true);
|
||||
SetValueForKey(ConstString(key), enum_value, true);
|
||||
} else {
|
||||
error.SetErrorString("dictionaries that can contain multiple types "
|
||||
"must subclass OptionValueArray");
|
||||
lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask(
|
||||
value.str().c_str(), m_type_mask, error));
|
||||
if (value_sp) {
|
||||
if (error.Fail())
|
||||
return error;
|
||||
m_value_was_set = true;
|
||||
SetValueForKey(ConstString(key), value_sp, true);
|
||||
} else {
|
||||
error.SetErrorString("dictionaries that can contain multiple types "
|
||||
"must subclass OptionValueArray");
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -68,9 +68,10 @@ Property::Property(const PropertyDefinition &definition)
|
|||
}
|
||||
case OptionValue::eTypeDictionary:
|
||||
// "definition.default_uint_value" is always a OptionValue::Type
|
||||
m_value_sp =
|
||||
std::make_shared<OptionValueDictionary>(OptionValue::ConvertTypeToMask(
|
||||
(OptionValue::Type)definition.default_uint_value));
|
||||
m_value_sp = std::make_shared<OptionValueDictionary>(
|
||||
OptionValue::ConvertTypeToMask(
|
||||
(OptionValue::Type)definition.default_uint_value),
|
||||
definition.enum_values);
|
||||
break;
|
||||
|
||||
case OptionValue::eTypeEnum:
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "lldb/Core/PluginManager.h"
|
||||
#include "lldb/Core/Section.h"
|
||||
#include "lldb/Core/StreamFile.h"
|
||||
#include "lldb/Interpreter/OptionValueDictionary.h"
|
||||
#include "lldb/Interpreter/OptionValueProperties.h"
|
||||
#include "lldb/Symbol/ObjectFile.h"
|
||||
#include "lldb/Target/Process.h"
|
||||
|
@ -91,6 +92,11 @@ public:
|
|||
m_collection_sp->GetPropertyAtIndexAsEnumeration(
|
||||
nullptr, ePropertyABI, llvm::Triple::UnknownEnvironment);
|
||||
}
|
||||
|
||||
OptionValueDictionary *ModuleABIMap() const {
|
||||
return m_collection_sp->GetPropertyAtIndexAsOptionValueDictionary(
|
||||
nullptr, ePropertyModuleABIMap);
|
||||
}
|
||||
};
|
||||
|
||||
static PluginProperties &GetGlobalPluginProperties() {
|
||||
|
@ -283,7 +289,41 @@ size_t ObjectFilePECOFF::GetModuleSpecifications(
|
|||
return llvm::Triple::MSVC;
|
||||
}();
|
||||
|
||||
llvm::Triple::EnvironmentType env = GetGlobalPluginProperties().ABI();
|
||||
// Check for a module-specific override.
|
||||
OptionValueSP module_env_option;
|
||||
const auto *map = GetGlobalPluginProperties().ModuleABIMap();
|
||||
if (map->GetNumValues() > 0) {
|
||||
// Step 1: Try with the exact file name.
|
||||
auto name = file.GetLastPathComponent();
|
||||
module_env_option = map->GetValueForKey(name);
|
||||
if (!module_env_option) {
|
||||
// Step 2: Try with the file name in lowercase.
|
||||
auto name_lower = name.GetStringRef().lower();
|
||||
module_env_option =
|
||||
map->GetValueForKey(ConstString(llvm::StringRef(name_lower)));
|
||||
}
|
||||
if (!module_env_option) {
|
||||
// Step 3: Try with the file name with ".debug" suffix stripped.
|
||||
auto name_stripped = name.GetStringRef();
|
||||
if (name_stripped.consume_back_insensitive(".debug")) {
|
||||
module_env_option = map->GetValueForKey(ConstString(name_stripped));
|
||||
if (!module_env_option) {
|
||||
// Step 4: Try with the file name in lowercase with ".debug" suffix
|
||||
// stripped.
|
||||
auto name_lower = name_stripped.lower();
|
||||
module_env_option =
|
||||
map->GetValueForKey(ConstString(llvm::StringRef(name_lower)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
llvm::Triple::EnvironmentType env;
|
||||
if (module_env_option)
|
||||
env =
|
||||
(llvm::Triple::EnvironmentType)module_env_option->GetEnumerationValue();
|
||||
else
|
||||
env = GetGlobalPluginProperties().ABI();
|
||||
|
||||
if (env == llvm::Triple::UnknownEnvironment)
|
||||
env = default_env;
|
||||
|
||||
|
|
|
@ -6,4 +6,9 @@ let Definition = "objectfilepecoff" in {
|
|||
DefaultEnumValue<"llvm::Triple::UnknownEnvironment">,
|
||||
EnumValues<"OptionEnumValues(g_abi_enums)">,
|
||||
Desc<"ABI to use when loading a PE/COFF module. This configures the C++ ABI used, which affects things like the handling of class layout. Accepted values are: `msvc` for the MSVC ABI, `gnu` for the MinGW / Itanium ABI, and `default` to follow the default target if it is a Windows triple or use the MSVC ABI by default.">;
|
||||
def ModuleABIMap: Property<"module-abi", "Dictionary">,
|
||||
Global,
|
||||
ElementType<"Enum">,
|
||||
EnumValues<"OptionEnumValues(g_abi_enums)">,
|
||||
Desc<"A mapping of ABI override to use for specific modules. The module name is matched by its file name with extension. These versions are checked in sequence: exact, lowercase, exact with '.debug' suffix stripped, lowercase with '.debug' suffix stripped. Accepted values are: `msvc` for the MSVC ABI, `gnu` for the MinGW / Itanium ABI, and `default` to follow the default target if it is a Windows triple or use the MSVC ABI by default.">;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
# RUN: yaml2obj %s -o %t
|
||||
# RUN: yaml2obj %s -o %t.debug
|
||||
# RUN: mkdir -p %t.dir
|
||||
# RUN: yaml2obj %s -o %t.dir/UPPER_CASE
|
||||
# RUN: yaml2obj %s -o %t.dir/UPPER_CASE.debug
|
||||
|
||||
## Default ABI is msvc:
|
||||
# RUN: %lldb -O "settings set plugin.object-file.pe-coff.abi msvc" \
|
||||
|
@ -10,6 +14,57 @@
|
|||
# RUN: -f %t -o "image list --triple --basename" -o exit | \
|
||||
# RUN: FileCheck -DABI=gnu -DFILENAME=%basename_t.tmp %s
|
||||
|
||||
## Default ABI is msvc, module override is gnu:
|
||||
# RUN: %lldb -O "settings set plugin.object-file.pe-coff.abi msvc" \
|
||||
# RUN: -O "settings append plugin.object-file.pe-coff.module-abi %basename_t.tmp=gnu" \
|
||||
# RUN: -f %t -o "image list --triple --basename" -o exit | \
|
||||
# RUN: FileCheck -DABI=gnu -DFILENAME=%basename_t.tmp %s
|
||||
|
||||
## Default ABI is gnu, module override is msvc:
|
||||
# RUN: %lldb -O "settings set plugin.object-file.pe-coff.abi gnu" \
|
||||
# RUN: -O "settings append plugin.object-file.pe-coff.module-abi %basename_t.tmp=msvc" \
|
||||
# RUN: -f %t -o "image list --triple --basename" -o exit | \
|
||||
# RUN: FileCheck -DABI=msvc -DFILENAME=%basename_t.tmp %s
|
||||
|
||||
## Default ABI is msvc, module override is gnu (with .debug suffix):
|
||||
# RUN: %lldb -O "settings set plugin.object-file.pe-coff.abi msvc" \
|
||||
# RUN: -O "settings append plugin.object-file.pe-coff.module-abi %basename_t.tmp=gnu" \
|
||||
# RUN: -f %t.debug -o "image list --triple --basename" -o exit | \
|
||||
# RUN: FileCheck -DABI=gnu -DFILENAME=%basename_t.tmp.debug %s
|
||||
|
||||
## Default ABI is gnu, module override is msvc (with .debug suffix):
|
||||
# RUN: %lldb -O "settings set plugin.object-file.pe-coff.abi gnu" \
|
||||
# RUN: -O "settings append plugin.object-file.pe-coff.module-abi %basename_t.tmp=msvc" \
|
||||
# RUN: -f %t.debug -o "image list --triple --basename" -o exit | \
|
||||
# RUN: FileCheck -DABI=msvc -DFILENAME=%basename_t.tmp.debug %s
|
||||
|
||||
## Check that case-sensitive match is chosen before lower-case:
|
||||
# RUN: %lldb -O "settings set plugin.object-file.pe-coff.abi msvc" \
|
||||
# RUN: -O "settings append plugin.object-file.pe-coff.module-abi upper_case=msvc" \
|
||||
# RUN: -O "settings append plugin.object-file.pe-coff.module-abi UPPER_CASE=gnu" \
|
||||
# RUN: -f %t.dir/UPPER_CASE -o "image list --triple --basename" -o exit | \
|
||||
# RUN: FileCheck -DABI=gnu -DFILENAME=UPPER_CASE %s
|
||||
|
||||
## Check that lower-case match with .debug suffix is chosen before case-sensitive match without .debug suffix:
|
||||
# RUN: %lldb -O "settings set plugin.object-file.pe-coff.abi msvc" \
|
||||
# RUN: -O "settings append plugin.object-file.pe-coff.module-abi UPPER_CASE=msvc" \
|
||||
# RUN: -O "settings append plugin.object-file.pe-coff.module-abi upper_case.debug=gnu" \
|
||||
# RUN: -f %t.dir/UPPER_CASE.debug -o "image list --triple --basename" -o exit | \
|
||||
# RUN: FileCheck -DABI=gnu -DFILENAME=UPPER_CASE.debug %s
|
||||
|
||||
## Check that case-sensitive match without .debug suffix is chosen before lower-case match without .debug suffix:
|
||||
# RUN: %lldb -O "settings set plugin.object-file.pe-coff.abi msvc" \
|
||||
# RUN: -O "settings append plugin.object-file.pe-coff.module-abi upper_case.debug=msvc" \
|
||||
# RUN: -O "settings append plugin.object-file.pe-coff.module-abi UPPER_CASE.debug=gnu" \
|
||||
# RUN: -f %t.dir/UPPER_CASE.debug -o "image list --triple --basename" -o exit | \
|
||||
# RUN: FileCheck -DABI=gnu -DFILENAME=UPPER_CASE.debug %s
|
||||
|
||||
## Check that lower-case match without .debug suffix works:
|
||||
# RUN: %lldb -O "settings set plugin.object-file.pe-coff.abi msvc" \
|
||||
# RUN: -O "settings append plugin.object-file.pe-coff.module-abi upper_case.debug=gnu" \
|
||||
# RUN: -f %t.dir/UPPER_CASE.debug -o "image list --triple --basename" -o exit | \
|
||||
# RUN: FileCheck -DABI=gnu -DFILENAME=UPPER_CASE.debug %s
|
||||
|
||||
# CHECK-LABEL: image list --triple --basename
|
||||
# CHECK-NEXT: x86_64-pc-windows-[[ABI]] [[FILENAME]]
|
||||
|
||||
|
|
Loading…
Reference in New Issue