Skip to content

Commit 50ca44e

Browse files
artemdinaburgkumarak
authored andcommitted
deserialize empty strings and widechars
1 parent 2bef722 commit 50ca44e

File tree

6 files changed

+98
-11
lines changed

6 files changed

+98
-11
lines changed

include/patchestry/Ghidra/PcodeOperations.hpp

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ namespace patchestry::ghidra {
4747
VARNODE_FUNCTION,
4848
VARNODE_TEMPORARY,
4949
VARNODE_CONSTANT,
50-
VARNODE_STRING
50+
VARNODE_STRING,
5151
};
5252

5353
static Varnode::Kind convertToKind(const std::string &kdd) {
@@ -67,6 +67,47 @@ namespace patchestry::ghidra {
6767
return iter != kind_map.end() ? iter->second : VARNODE_UNKNOWN;
6868
}
6969

70+
std::string dump() const {
71+
std::string result;
72+
result += "Varnode {\n";
73+
74+
// Convert kind to string
75+
std::string kind_str;
76+
switch (kind) {
77+
case VARNODE_UNKNOWN: kind_str = "UNKNOWN"; break;
78+
case VARNODE_GLOBAL: kind_str = "GLOBAL"; break;
79+
case VARNODE_LOCAL: kind_str = "LOCAL"; break;
80+
case VARNODE_PARAM: kind_str = "PARAM"; break;
81+
case VARNODE_FUNCTION: kind_str = "FUNCTION"; break;
82+
case VARNODE_TEMPORARY: kind_str = "TEMPORARY"; break;
83+
case VARNODE_CONSTANT: kind_str = "CONSTANT"; break;
84+
case VARNODE_STRING: kind_str = "STRING"; break;
85+
}
86+
87+
result += " kind: " + kind_str + "\n";
88+
result += " size: " + std::to_string(size) + "\n";
89+
result += " type_key: " + type_key + "\n";
90+
91+
if (operation) {
92+
result += " operation: " + *operation + "\n";
93+
}
94+
if (function) {
95+
result += " function: " + *function + "\n";
96+
}
97+
if (value) {
98+
result += " value: " + std::to_string(*value) + "\n";
99+
}
100+
if (string_value) {
101+
result += " string_value: " + *string_value + "\n";
102+
}
103+
if (global) {
104+
result += " global: " + *global + "\n";
105+
}
106+
107+
result += "}";
108+
return result;
109+
}
110+
70111
Kind kind;
71112
uint32_t size;
72113
std::string type_key;

include/patchestry/Ghidra/PcodeTypes.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ namespace patchestry::ghidra {
2424
VT_INTEGER,
2525
VT_FLOAT,
2626
VT_CHAR,
27+
VT_WIDECHAR,
2728
VT_POINTER,
2829
VT_FUNCTION,
2930
VT_ARRAY,
@@ -49,7 +50,8 @@ namespace patchestry::ghidra {
4950
{ "enum", VT_ENUM},
5051
{ "typedef", VT_TYPEDEF},
5152
{"undefined", VT_UNDEFINED},
52-
{ "void", VT_VOID}
53+
{ "void", VT_VOID},
54+
{"WideCharDataType", VT_WIDECHAR}
5355
};
5456

5557
// if kind is not present in the map, return vt_invalid

lib/patchestry/AST/FunctionBuilder.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -311,9 +311,13 @@ namespace patchestry::ast {
311311
* blocks, or if the function definition cannot be created.
312312
*/
313313
clang::FunctionDecl *FunctionBuilder::create_definition(clang::ASTContext &ctx) {
314-
if (function.get().name.empty() || function.get().basic_blocks.empty()) {
315-
LOG(ERROR) << "Can't create function definition. Missing function name or has no "
316-
"basic blocks.\n";
314+
if (function.get().name.empty()) {
315+
LOG(ERROR) << "Can't create function definition. Missing function name.\n";
316+
return {};
317+
}
318+
319+
if (function.get().basic_blocks.empty()) {
320+
LOG(ERROR) << "Can't create function definition for '" << function.get().name << "'. Function has no basic blocks.\n";
317321
return {};
318322
}
319323

lib/patchestry/AST/OperationBuilder.cpp

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -258,17 +258,40 @@ namespace patchestry::ast {
258258

259259
if (!vnode.string_value) {
260260
LOG(ERROR) << "No string value found, invalid varnode.\n";
261+
LOG(ERROR) << vnode.dump() << "\n";
261262
return {};
262263
}
263264

265+
// Determine if this is a wide string based on the type
266+
bool is_wide = false;
267+
if (!vnode.type_key.empty()) {
268+
if (type_builder().get_serialized_types().contains(vnode.type_key)) {
269+
auto type = type_builder().get_serialized_types().at(vnode.type_key);
270+
is_wide = type->isWideCharType();
271+
}
272+
}
273+
274+
// For empty string, we still need an array of size 1 for the null terminator
275+
const size_t string_length = vnode.string_value->length();
276+
const size_t array_size = string_length + 1; // +1 for null terminator
277+
278+
// Create the appropriate array type
279+
auto char_type = is_wide ? ctx.WideCharTy : ctx.CharTy;
264280
auto string_array = ctx.getConstantArrayType(
265-
ctx.CharTy.withConst(), llvm::APInt(32, vnode.string_value.value().size() + 1),
266-
nullptr, clang::ArraySizeModifier::Normal, 0
281+
char_type.withConst(),
282+
llvm::APInt(32, array_size),
283+
nullptr,
284+
clang::ArraySizeModifier::Normal,
285+
0
267286
);
268287

269288
return clang::StringLiteral::Create(
270-
ctx, vnode.string_value.value(), clang::StringLiteralKind::Ordinary, false,
271-
string_array, clang::SourceLocation()
289+
ctx,
290+
*vnode.string_value, // Use the string value directly
291+
is_wide ? clang::StringLiteralKind::Wide : clang::StringLiteralKind::Ordinary,
292+
false,
293+
string_array,
294+
clang::SourceLocation()
272295
);
273296
}
274297

lib/patchestry/AST/TypeBuilder.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ namespace patchestry::ast {
9494
case VarnodeType::VT_CHAR:
9595
return ctx.CharTy;
9696

97+
case VarnodeType::VT_WIDECHAR:
98+
return ctx.WideCharTy;
99+
97100
case VarnodeType::VT_FLOAT:
98101
return getTypeFromSize(
99102
ctx, vnode_type->size * TypeBuilder::num_bits_in_byte, /*is_signed=*/false,

lib/patchestry/Ghidra/JsonDeserialize.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,16 @@ namespace patchestry::ghidra {
4343
return std::nullopt;
4444
}
4545

46+
template< typename ObjectType >
47+
constexpr std::optional< std::string >
48+
get_string_with_empty(const ObjectType &obj, const char *field) {
49+
if (auto value = (obj.getString)(field)) {
50+
// Return the string even if it's empty
51+
return value->str();
52+
}
53+
return std::nullopt;
54+
}
55+
4656
template< typename ObjectType >
4757
std::string
4858
get_string(const ObjectType &obj, const char *field, std::string default_value = "") {
@@ -121,6 +131,7 @@ namespace patchestry::ghidra {
121131
case VarnodeType::Kind::VT_INTEGER:
122132
case VarnodeType::Kind::VT_FLOAT:
123133
case VarnodeType::Kind::VT_CHAR:
134+
case VarnodeType::Kind::VT_WIDECHAR:
124135
case VarnodeType::Kind::VT_VOID:
125136
deserialize_buildin(
126137
*dynamic_cast< BuiltinType * >(vnode_type.get()),
@@ -187,6 +198,7 @@ namespace patchestry::ghidra {
187198
auto name = get_string(type_obj, "name");
188199
auto size = static_cast< uint32_t >(type_obj.getInteger("size").value_or(0));
189200
auto kind_str = get_string(type_obj, "kind");
201+
LOG(INFO) << "Attempting to convert kind string: [" << kind_str << "]" << "\n";
190202
auto kind = VarnodeType::convertToKind(kind_str);
191203
switch (kind) {
192204
case VarnodeType::Kind::VT_INVALID: {
@@ -197,6 +209,7 @@ namespace patchestry::ghidra {
197209
case VarnodeType::Kind::VT_INTEGER:
198210
case VarnodeType::Kind::VT_FLOAT:
199211
case VarnodeType::Kind::VT_CHAR:
212+
case VarnodeType::Kind::VT_WIDECHAR:
200213
return std::make_shared< BuiltinType >(name, kind, size);
201214
case VarnodeType::Kind::VT_ARRAY:
202215
return std::make_shared< ArrayType >(name, kind, size);
@@ -227,6 +240,7 @@ namespace patchestry::ghidra {
227240
varnode.kind == VarnodeType::Kind::VT_BOOLEAN
228241
|| varnode.kind == VarnodeType::Kind::VT_INTEGER
229242
|| varnode.kind == VarnodeType::Kind::VT_CHAR
243+
|| varnode.kind == VarnodeType::Kind::VT_WIDECHAR
230244
|| varnode.kind == VarnodeType::Kind::VT_FLOAT
231245
|| varnode.kind == VarnodeType::Kind::VT_VOID
232246
);
@@ -381,7 +395,7 @@ namespace patchestry::ghidra {
381395

382396
auto set_field_if_valid = [](const std::optional< std::string > &field,
383397
std::optional< std::string > &vnode_field) {
384-
if (field && !field->empty()) {
398+
if (field) {
385399
vnode_field = *field;
386400
}
387401
};
@@ -391,7 +405,7 @@ namespace patchestry::ghidra {
391405
set_field_if_valid(get_string_if_valid(var_obj, "operation"), vnode.operation);
392406
set_field_if_valid(get_string_if_valid(var_obj, "function"), vnode.function);
393407
set_field_if_valid(get_string_if_valid(var_obj, "global"), vnode.global);
394-
set_field_if_valid(get_string_if_valid(var_obj, "string_value"), vnode.string_value);
408+
set_field_if_valid(get_string_with_empty(var_obj, "string_value"), vnode.string_value);
395409
vnode.value = var_obj.getInteger("value");
396410
return vnode;
397411
}

0 commit comments

Comments
 (0)