Skip to content

Commit f2a87e1

Browse files
committedOct 3, 2024
idaloader: improved .pdata performance, add savevmx/restvmx
1 parent 28cf5b3 commit f2a87e1

File tree

2 files changed

+89
-65
lines changed

2 files changed

+89
-65
lines changed
 

‎idaloader.cpp

+80-65
Original file line numberDiff line numberDiff line change
@@ -23,87 +23,71 @@ bool exclude_unneeded_sections = true;
2323

2424
std::string DoNameGen(const std::string& libName, int id, int version); // namegen.cpp
2525

26-
void label_regsaveloads(ea_t start, ea_t end)
26+
struct saverest_pattern
2727
{
28-
// "std %r14, -0x98(%sp)" followed by "std %r15, -0x90(%sp)"
29-
uint8 save_pattern[] = {
30-
0xF9, 0xC1, 0xFF, 0x68, 0xF9, 0xE1, 0xFF, 0x70
31-
};
32-
// "ld %r14, -0x98(%sp)" followed by "ld %r15, -0x90(%sp)"
33-
uint8 load_pattern[] = {
34-
0xE9, 0xC1, 0xFF, 0x68, 0xE9, 0xE1, 0xFF, 0x70
35-
};
36-
// "stfd %f14, -0x90(%r12)" followed by "stfd %f15, -0x88(%r12)"
37-
uint8 savef_pattern[] = {
38-
0xD9, 0xCC, 0xFF, 0x70, 0xD9, 0xEC, 0xFF, 0x78
39-
};
40-
// "lfd %f14, -0x90(%r12)" followed by "lfd %f15, -0x88(%r12)"
41-
uint8 loadf_pattern[] = {
42-
0xC9, 0xCC, 0xFF, 0x70, 0xC9, 0xEC, 0xFF, 0x78
43-
};
44-
45-
46-
uint8* patterns[] = {
47-
save_pattern,
48-
load_pattern,
49-
savef_pattern,
50-
loadf_pattern
51-
};
52-
const char* pattern_labels[] = {
53-
"__savegprlr_%d",
54-
"__restgprlr_%d",
55-
"__savefpr_%d",
56-
"__restfpr_%d"
57-
};
28+
const char* name;
29+
const std::vector<uint8_t> pattern;
30+
bool is_prolog;
31+
int start_reg;
32+
int end_reg;
33+
int fn_size;
34+
int final_size;
35+
};
5836

59-
init_ignore_micro();
37+
std::list<saverest_pattern> patterns =
38+
{
39+
{ "__savegprlr_%d", {0xF9, 0xC1, 0xFF, 0x68, 0xF9, 0xE1, 0xFF, 0x70}, true, 14, 32, 4, 12 },
40+
{ "__restgprlr_%d", {0xE9, 0xC1, 0xFF, 0x68, 0xE9, 0xE1, 0xFF, 0x70}, false, 14, 32, 4, 16 },
6041

61-
for (int pat_idx = 0; pat_idx < 4; pat_idx++)
42+
{ "__savefpr_%d", {0xD9, 0xCC, 0xFF, 0x70, 0xD9, 0xEC, 0xFF, 0x78}, true, 14, 32, 4, 8 },
43+
{ "__restfpr_%d", {0xC9, 0xCC, 0xFF, 0x70, 0xC9, 0xEC, 0xFF, 0x78}, false, 14, 32, 4, 8 },
44+
45+
{ "__savevmx_%d", {0x39, 0x60, 0xFE, 0xE0, 0x7D, 0xCB, 0x61, 0xCE}, true, 14, 32, 8, 12 },
46+
{ "__restvmx_%d", {0x39, 0x60, 0xFE, 0xE0, 0x7D, 0xCB, 0x60, 0xCE}, false, 14, 32, 8, 12 },
47+
48+
// vmx128, same name as above
49+
{ "__savevmx_%d", {0x39, 0x60, 0xFC, 0x00, 0x10, 0x0B, 0x61, 0xCB}, true, 64, 128, 8, 12 },
50+
{ "__restvmx_%d", {0x39, 0x60, 0xFC, 0x00, 0x10, 0x0B, 0x60, 0xCB}, false, 64, 128, 8, 12 },
51+
};
52+
53+
void label_regsaveloads(ea_t start, ea_t end)
54+
{
55+
for (auto& pattern : patterns)
6256
{
6357
ea_t addr = start;
6458

6559
while (addr != BADADDR)
6660
{
67-
addr = bin_search(addr, end, patterns[pat_idx], NULL, 8, BIN_SEARCH_CASE | BIN_SEARCH_FORWARD);
61+
addr = bin_search(addr, end, pattern.pattern.data(), NULL, 8, BIN_SEARCH_CASE | BIN_SEARCH_FORWARD);
6862
if (addr == BADADDR)
6963
break;
7064

71-
for (int i = 14; i < 32; i++)
65+
for (int i = pattern.start_reg; i < pattern.end_reg; i++)
7266
{
73-
int size = 4;
74-
75-
// final one is 0xC bytes when saving, 0x10 when loading
76-
// (final fpr pattern is 0x8 when saving/loading)
77-
if (i == 31)
78-
{
79-
size = (pat_idx == 0) ? 0xC : 0x10;
80-
if (pat_idx > 1) size = 8;
81-
}
67+
int size = pattern.fn_size;
68+
if (i + 1 == pattern.end_reg)
69+
size = pattern.final_size;
8270

8371
// reset addr
8472
del_items(addr, 0, 8);
8573
create_insn(addr);
8674

87-
set_name(addr, qstring().sprnt(pattern_labels[pat_idx], i).c_str(), SN_FORCE);
75+
set_name(addr, qstring().sprnt(pattern.name, i).c_str(), SN_FORCE);
8876

8977
func_t fn(addr, addr + size);
9078
fn.flags |= FUNC_OUTLINE | FUNC_HIDDEN;
9179
add_func_ex(&fn);
9280

9381
// Mark save/rest functions as prolog/epilog to hide them from decompiler
9482
int hide_size = size;
95-
if (i == 31)
96-
hide_size -= 4; // don't hide last blr
83+
if (i + 1 == pattern.end_reg)
84+
hide_size -= 4; // don't hide last blr
9785
for (int insn = 0; insn < hide_size; insn += 4)
9886
{
99-
if (pat_idx == 0 || pat_idx == 2)
100-
{
101-
mark_prolog_insn(addr + insn);
102-
}
103-
else
104-
{
105-
mark_epilog_insn(addr + insn);
106-
}
87+
if (pattern.is_prolog)
88+
mark_prolog_insn(addr + insn);
89+
else
90+
mark_epilog_insn(addr + insn);
10791
}
10892

10993
addr += size;
@@ -114,6 +98,8 @@ void label_regsaveloads(ea_t start, ea_t end)
11498

11599
void pe_add_sections(XEXFile& file)
116100
{
101+
init_ignore_micro();
102+
117103
for (const auto& section : file.sections())
118104
{
119105
// New buffer for section name so we can null-terminate it
@@ -206,21 +192,37 @@ void pe_add_sections(XEXFile& file)
206192
if (sec_addr + sec_size > file.image_size())
207193
sec_size = file.image_size() - sec_addr;
208194

209-
// Store function addrs from .pdata inside a std::vector, so we can iterate over them in reverse
210-
std::vector<uint32_t> funcs;
195+
struct RUNTIME_FUNCTION_INFO // bitfield portion of RUNTIME_FUNCTION
196+
{
197+
uint32_t PrologLength : 8;
198+
uint32_t FunctionLength : 22;
199+
uint32_t FunctionType : 2;
200+
201+
inline xex::RuntimeFunctionType RuntimeFunctionType() {
202+
return (xex::RuntimeFunctionType)FunctionType;
203+
}
204+
};
205+
206+
// Read function addrs from .pdata into vector so we can get a count before asking IDA to create functions for them
207+
std::unordered_map<uint32_t, RUNTIME_FUNCTION_INFO> funcs;
211208
int offset = 0;
212209
while (offset < sec_size)
213210
{
214211
create_data(seg_addr + offset, dword_flag(), 4, BADNODE);
215212
create_data(seg_addr + offset + 4, dword_flag(), 4, BADNODE);
216213

217214
auto* fn_ptr = reinterpret_cast<const xe::be<uint32_t>*>(file.pe_data() + sec_addr + offset);
218-
ea_t fn = *fn_ptr;
215+
uint32_t fn_ea = fn_ptr[0];
219216

220-
funcs.push_back(fn);
217+
if (fn_ea)
218+
{
219+
uint32_t fn_info_raw = fn_ptr[1]; // endian-swap the field for us
220+
RUNTIME_FUNCTION_INFO fn_info = *(RUNTIME_FUNCTION_INFO*)&fn_info_raw; // and then convert to RUNTIME_FUNCTION_INFO
221+
funcs.insert({ fn_ea, fn_info });
221222

222-
// Delete useless .pdata -> fn xref
223-
del_dref(seg_addr + offset, fn);
223+
// Delete useless .pdata -> fn xref
224+
del_dref(seg_addr + offset, fn_ea);
225+
}
224226

225227
offset += 8;
226228
}
@@ -236,12 +238,25 @@ void pe_add_sections(XEXFile& file)
236238

237239
show_wait_box(msg_text);
238240

239-
// Iterate over functions in reverse, so hopefully they'll be marked with correct lengths
240241
size_t num = 0;
241-
for (std::vector<uint32_t>::reverse_iterator i = funcs.rbegin(); i != funcs.rend(); ++i)
242+
for (auto& kvp : funcs)
242243
{
243-
create_insn(*i);
244-
add_func(*i);
244+
if (!get_fchunk(kvp.first))
245+
{
246+
if (create_insn(kvp.first))
247+
{
248+
show_auto(kvp.first);
249+
250+
// Don't create function for savevmx/restvmx
251+
auto fn_type = kvp.second.RuntimeFunctionType();
252+
if (fn_type != xex::RuntimeFunctionType::SaveMillicode && fn_type != xex::RuntimeFunctionType::RestoreMillicode)
253+
{
254+
func_t fn(kvp.first, kvp.first + (kvp.second.FunctionLength * 4));
255+
add_func_ex(&fn);
256+
}
257+
}
258+
}
259+
245260
if (user_cancelled())
246261
break;
247262

‎xex_structs.hpp

+9
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,15 @@ namespace xex {
147147
uint8_t DataDigest[0x14]; // Digest of the next page + next page descriptor
148148
};
149149
static_assert(sizeof(HvPageInfo) == 0x18, "xex:HvPageInfo");
150+
151+
// FunctionType inside RUNTIME_FUNCTION
152+
enum class RuntimeFunctionType
153+
{
154+
SaveMillicode = 0x0,
155+
NoHandler = 0x1,
156+
RestoreMillicode = 0x2,
157+
Handler = 0x3,
158+
};
150159
};
151160

152161
namespace xex2 {

0 commit comments

Comments
 (0)
Please sign in to comment.