Skip to content

Commit 3c86789

Browse files
alvinhochunmstorsjo
authored andcommitted
[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
1 parent 4d12378 commit 3c86789

File tree

6 files changed

+128
-12
lines changed

6 files changed

+128
-12
lines changed

lldb/include/lldb/Interpreter/OptionValueDictionary.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,18 @@
1212
#include <map>
1313

1414
#include "lldb/Interpreter/OptionValue.h"
15+
#include "lldb/lldb-private-types.h"
1516

1617
namespace lldb_private {
1718

1819
class OptionValueDictionary
1920
: public Cloneable<OptionValueDictionary, OptionValue> {
2021
public:
2122
OptionValueDictionary(uint32_t type_mask = UINT32_MAX,
23+
OptionEnumValues enum_values = OptionEnumValues(),
2224
bool raw_value_dump = true)
23-
: m_type_mask(type_mask), m_raw_value_dump(raw_value_dump) {}
25+
: m_type_mask(type_mask), m_enum_values(enum_values),
26+
m_raw_value_dump(raw_value_dump) {}
2427

2528
~OptionValueDictionary() override = default;
2629

@@ -75,6 +78,7 @@ class OptionValueDictionary
7578
protected:
7679
typedef std::map<ConstString, lldb::OptionValueSP> collection;
7780
uint32_t m_type_mask;
81+
OptionEnumValues m_enum_values;
7882
collection m_values;
7983
bool m_raw_value_dump;
8084
};

lldb/source/Interpreter/OptionValueDictionary.cpp

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@
88

99
#include "lldb/Interpreter/OptionValueDictionary.h"
1010

11-
#include "llvm/ADT/StringRef.h"
1211
#include "lldb/DataFormatters/FormatManager.h"
12+
#include "lldb/Interpreter/OptionValueEnumeration.h"
1313
#include "lldb/Interpreter/OptionValueString.h"
1414
#include "lldb/Utility/Args.h"
1515
#include "lldb/Utility/State.h"
16+
#include "llvm/ADT/StringRef.h"
1617

1718
using namespace lldb;
1819
using namespace lldb_private;
@@ -161,16 +162,26 @@ Status OptionValueDictionary::SetArgs(const Args &args,
161162
return error;
162163
}
163164

164-
lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask(
165-
value.str().c_str(), m_type_mask, error));
166-
if (value_sp) {
165+
if (m_type_mask == 1u << eTypeEnum) {
166+
auto enum_value =
167+
std::make_shared<OptionValueEnumeration>(m_enum_values, 0);
168+
error = enum_value->SetValueFromString(value);
167169
if (error.Fail())
168170
return error;
169171
m_value_was_set = true;
170-
SetValueForKey(ConstString(key), value_sp, true);
172+
SetValueForKey(ConstString(key), enum_value, true);
171173
} else {
172-
error.SetErrorString("dictionaries that can contain multiple types "
173-
"must subclass OptionValueArray");
174+
lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask(
175+
value.str().c_str(), m_type_mask, error));
176+
if (value_sp) {
177+
if (error.Fail())
178+
return error;
179+
m_value_was_set = true;
180+
SetValueForKey(ConstString(key), value_sp, true);
181+
} else {
182+
error.SetErrorString("dictionaries that can contain multiple types "
183+
"must subclass OptionValueArray");
184+
}
174185
}
175186
}
176187
break;

lldb/source/Interpreter/Property.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,10 @@ Property::Property(const PropertyDefinition &definition)
6868
}
6969
case OptionValue::eTypeDictionary:
7070
// "definition.default_uint_value" is always a OptionValue::Type
71-
m_value_sp =
72-
std::make_shared<OptionValueDictionary>(OptionValue::ConvertTypeToMask(
73-
(OptionValue::Type)definition.default_uint_value));
71+
m_value_sp = std::make_shared<OptionValueDictionary>(
72+
OptionValue::ConvertTypeToMask(
73+
(OptionValue::Type)definition.default_uint_value),
74+
definition.enum_values);
7475
break;
7576

7677
case OptionValue::eTypeEnum:

lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "lldb/Core/PluginManager.h"
1717
#include "lldb/Core/Section.h"
1818
#include "lldb/Core/StreamFile.h"
19+
#include "lldb/Interpreter/OptionValueDictionary.h"
1920
#include "lldb/Interpreter/OptionValueProperties.h"
2021
#include "lldb/Symbol/ObjectFile.h"
2122
#include "lldb/Target/Process.h"
@@ -91,6 +92,11 @@ class PluginProperties : public Properties {
9192
m_collection_sp->GetPropertyAtIndexAsEnumeration(
9293
nullptr, ePropertyABI, llvm::Triple::UnknownEnvironment);
9394
}
95+
96+
OptionValueDictionary *ModuleABIMap() const {
97+
return m_collection_sp->GetPropertyAtIndexAsOptionValueDictionary(
98+
nullptr, ePropertyModuleABIMap);
99+
}
94100
};
95101

96102
static PluginProperties &GetGlobalPluginProperties() {
@@ -283,7 +289,41 @@ size_t ObjectFilePECOFF::GetModuleSpecifications(
283289
return llvm::Triple::MSVC;
284290
}();
285291

286-
llvm::Triple::EnvironmentType env = GetGlobalPluginProperties().ABI();
292+
// Check for a module-specific override.
293+
OptionValueSP module_env_option;
294+
const auto *map = GetGlobalPluginProperties().ModuleABIMap();
295+
if (map->GetNumValues() > 0) {
296+
// Step 1: Try with the exact file name.
297+
auto name = file.GetLastPathComponent();
298+
module_env_option = map->GetValueForKey(name);
299+
if (!module_env_option) {
300+
// Step 2: Try with the file name in lowercase.
301+
auto name_lower = name.GetStringRef().lower();
302+
module_env_option =
303+
map->GetValueForKey(ConstString(llvm::StringRef(name_lower)));
304+
}
305+
if (!module_env_option) {
306+
// Step 3: Try with the file name with ".debug" suffix stripped.
307+
auto name_stripped = name.GetStringRef();
308+
if (name_stripped.consume_back_insensitive(".debug")) {
309+
module_env_option = map->GetValueForKey(ConstString(name_stripped));
310+
if (!module_env_option) {
311+
// Step 4: Try with the file name in lowercase with ".debug" suffix
312+
// stripped.
313+
auto name_lower = name_stripped.lower();
314+
module_env_option =
315+
map->GetValueForKey(ConstString(llvm::StringRef(name_lower)));
316+
}
317+
}
318+
}
319+
}
320+
llvm::Triple::EnvironmentType env;
321+
if (module_env_option)
322+
env =
323+
(llvm::Triple::EnvironmentType)module_env_option->GetEnumerationValue();
324+
else
325+
env = GetGlobalPluginProperties().ABI();
326+
287327
if (env == llvm::Triple::UnknownEnvironment)
288328
env = default_env;
289329

lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFFProperties.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,9 @@ let Definition = "objectfilepecoff" in {
66
DefaultEnumValue<"llvm::Triple::UnknownEnvironment">,
77
EnumValues<"OptionEnumValues(g_abi_enums)">,
88
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.">;
9+
def ModuleABIMap: Property<"module-abi", "Dictionary">,
10+
Global,
11+
ElementType<"Enum">,
12+
EnumValues<"OptionEnumValues(g_abi_enums)">,
13+
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.">;
914
}

lldb/test/Shell/ObjectFile/PECOFF/settings-abi.yaml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
# RUN: yaml2obj %s -o %t
2+
# RUN: yaml2obj %s -o %t.debug
3+
# RUN: mkdir -p %t.dir
4+
# RUN: yaml2obj %s -o %t.dir/UPPER_CASE
5+
# RUN: yaml2obj %s -o %t.dir/UPPER_CASE.debug
26

37
## Default ABI is msvc:
48
# RUN: %lldb -O "settings set plugin.object-file.pe-coff.abi msvc" \
@@ -10,6 +14,57 @@
1014
# RUN: -f %t -o "image list --triple --basename" -o exit | \
1115
# RUN: FileCheck -DABI=gnu -DFILENAME=%basename_t.tmp %s
1216

17+
## Default ABI is msvc, module override is gnu:
18+
# RUN: %lldb -O "settings set plugin.object-file.pe-coff.abi msvc" \
19+
# RUN: -O "settings append plugin.object-file.pe-coff.module-abi %basename_t.tmp=gnu" \
20+
# RUN: -f %t -o "image list --triple --basename" -o exit | \
21+
# RUN: FileCheck -DABI=gnu -DFILENAME=%basename_t.tmp %s
22+
23+
## Default ABI is gnu, module override is msvc:
24+
# RUN: %lldb -O "settings set plugin.object-file.pe-coff.abi gnu" \
25+
# RUN: -O "settings append plugin.object-file.pe-coff.module-abi %basename_t.tmp=msvc" \
26+
# RUN: -f %t -o "image list --triple --basename" -o exit | \
27+
# RUN: FileCheck -DABI=msvc -DFILENAME=%basename_t.tmp %s
28+
29+
## Default ABI is msvc, module override is gnu (with .debug suffix):
30+
# RUN: %lldb -O "settings set plugin.object-file.pe-coff.abi msvc" \
31+
# RUN: -O "settings append plugin.object-file.pe-coff.module-abi %basename_t.tmp=gnu" \
32+
# RUN: -f %t.debug -o "image list --triple --basename" -o exit | \
33+
# RUN: FileCheck -DABI=gnu -DFILENAME=%basename_t.tmp.debug %s
34+
35+
## Default ABI is gnu, module override is msvc (with .debug suffix):
36+
# RUN: %lldb -O "settings set plugin.object-file.pe-coff.abi gnu" \
37+
# RUN: -O "settings append plugin.object-file.pe-coff.module-abi %basename_t.tmp=msvc" \
38+
# RUN: -f %t.debug -o "image list --triple --basename" -o exit | \
39+
# RUN: FileCheck -DABI=msvc -DFILENAME=%basename_t.tmp.debug %s
40+
41+
## Check that case-sensitive match is chosen before lower-case:
42+
# RUN: %lldb -O "settings set plugin.object-file.pe-coff.abi msvc" \
43+
# RUN: -O "settings append plugin.object-file.pe-coff.module-abi upper_case=msvc" \
44+
# RUN: -O "settings append plugin.object-file.pe-coff.module-abi UPPER_CASE=gnu" \
45+
# RUN: -f %t.dir/UPPER_CASE -o "image list --triple --basename" -o exit | \
46+
# RUN: FileCheck -DABI=gnu -DFILENAME=UPPER_CASE %s
47+
48+
## Check that lower-case match with .debug suffix is chosen before case-sensitive match without .debug suffix:
49+
# RUN: %lldb -O "settings set plugin.object-file.pe-coff.abi msvc" \
50+
# RUN: -O "settings append plugin.object-file.pe-coff.module-abi UPPER_CASE=msvc" \
51+
# RUN: -O "settings append plugin.object-file.pe-coff.module-abi upper_case.debug=gnu" \
52+
# RUN: -f %t.dir/UPPER_CASE.debug -o "image list --triple --basename" -o exit | \
53+
# RUN: FileCheck -DABI=gnu -DFILENAME=UPPER_CASE.debug %s
54+
55+
## Check that case-sensitive match without .debug suffix is chosen before lower-case match without .debug suffix:
56+
# RUN: %lldb -O "settings set plugin.object-file.pe-coff.abi msvc" \
57+
# RUN: -O "settings append plugin.object-file.pe-coff.module-abi upper_case.debug=msvc" \
58+
# RUN: -O "settings append plugin.object-file.pe-coff.module-abi UPPER_CASE.debug=gnu" \
59+
# RUN: -f %t.dir/UPPER_CASE.debug -o "image list --triple --basename" -o exit | \
60+
# RUN: FileCheck -DABI=gnu -DFILENAME=UPPER_CASE.debug %s
61+
62+
## Check that lower-case match without .debug suffix works:
63+
# RUN: %lldb -O "settings set plugin.object-file.pe-coff.abi msvc" \
64+
# RUN: -O "settings append plugin.object-file.pe-coff.module-abi upper_case.debug=gnu" \
65+
# RUN: -f %t.dir/UPPER_CASE.debug -o "image list --triple --basename" -o exit | \
66+
# RUN: FileCheck -DABI=gnu -DFILENAME=UPPER_CASE.debug %s
67+
1368
# CHECK-LABEL: image list --triple --basename
1469
# CHECK-NEXT: x86_64-pc-windows-[[ABI]] [[FILENAME]]
1570

0 commit comments

Comments
 (0)