ida-pro-mcp-xjoker 1.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ida_pro_mcp/__init__.py +0 -0
- ida_pro_mcp/__main__.py +6 -0
- ida_pro_mcp/ida_mcp/__init__.py +68 -0
- ida_pro_mcp/ida_mcp/api_analysis.py +1296 -0
- ida_pro_mcp/ida_mcp/api_core.py +337 -0
- ida_pro_mcp/ida_mcp/api_debug.py +617 -0
- ida_pro_mcp/ida_mcp/api_memory.py +304 -0
- ida_pro_mcp/ida_mcp/api_modify.py +406 -0
- ida_pro_mcp/ida_mcp/api_python.py +179 -0
- ida_pro_mcp/ida_mcp/api_resources.py +295 -0
- ida_pro_mcp/ida_mcp/api_stack.py +167 -0
- ida_pro_mcp/ida_mcp/api_types.py +480 -0
- ida_pro_mcp/ida_mcp/auth.py +166 -0
- ida_pro_mcp/ida_mcp/cache.py +232 -0
- ida_pro_mcp/ida_mcp/config.py +228 -0
- ida_pro_mcp/ida_mcp/framework.py +547 -0
- ida_pro_mcp/ida_mcp/http.py +859 -0
- ida_pro_mcp/ida_mcp/port_utils.py +104 -0
- ida_pro_mcp/ida_mcp/rpc.py +187 -0
- ida_pro_mcp/ida_mcp/server_manager.py +339 -0
- ida_pro_mcp/ida_mcp/sync.py +233 -0
- ida_pro_mcp/ida_mcp/tests/__init__.py +14 -0
- ida_pro_mcp/ida_mcp/tests/test_api_analysis.py +336 -0
- ida_pro_mcp/ida_mcp/tests/test_api_core.py +237 -0
- ida_pro_mcp/ida_mcp/tests/test_api_memory.py +207 -0
- ida_pro_mcp/ida_mcp/tests/test_api_modify.py +123 -0
- ida_pro_mcp/ida_mcp/tests/test_api_resources.py +199 -0
- ida_pro_mcp/ida_mcp/tests/test_api_stack.py +77 -0
- ida_pro_mcp/ida_mcp/tests/test_api_types.py +249 -0
- ida_pro_mcp/ida_mcp/ui.py +357 -0
- ida_pro_mcp/ida_mcp/utils.py +1186 -0
- ida_pro_mcp/ida_mcp/zeromcp/__init__.py +5 -0
- ida_pro_mcp/ida_mcp/zeromcp/jsonrpc.py +384 -0
- ida_pro_mcp/ida_mcp/zeromcp/mcp.py +883 -0
- ida_pro_mcp/ida_mcp.py +186 -0
- ida_pro_mcp/idalib_server.py +354 -0
- ida_pro_mcp/idalib_session_manager.py +259 -0
- ida_pro_mcp/server.py +1060 -0
- ida_pro_mcp/test.py +170 -0
- ida_pro_mcp_xjoker-1.0.1.dist-info/METADATA +405 -0
- ida_pro_mcp_xjoker-1.0.1.dist-info/RECORD +45 -0
- ida_pro_mcp_xjoker-1.0.1.dist-info/WHEEL +5 -0
- ida_pro_mcp_xjoker-1.0.1.dist-info/entry_points.txt +4 -0
- ida_pro_mcp_xjoker-1.0.1.dist-info/licenses/LICENSE +21 -0
- ida_pro_mcp_xjoker-1.0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"""Tests for api_resources MCP resource functions."""
|
|
2
|
+
|
|
3
|
+
# Import test framework from parent
|
|
4
|
+
from ..framework import (
|
|
5
|
+
test,
|
|
6
|
+
assert_valid_address,
|
|
7
|
+
assert_has_keys,
|
|
8
|
+
assert_non_empty,
|
|
9
|
+
get_any_function,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
# Import resource functions under test
|
|
13
|
+
from ..api_resources import (
|
|
14
|
+
idb_metadata_resource,
|
|
15
|
+
idb_segments_resource,
|
|
16
|
+
idb_entrypoints_resource,
|
|
17
|
+
cursor_resource,
|
|
18
|
+
selection_resource,
|
|
19
|
+
types_resource,
|
|
20
|
+
structs_resource,
|
|
21
|
+
struct_name_resource,
|
|
22
|
+
import_name_resource,
|
|
23
|
+
export_name_resource,
|
|
24
|
+
xrefs_from_resource,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
# Import sync module for IDAError
|
|
28
|
+
from ..sync import IDAError
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# ============================================================================
|
|
32
|
+
# Tests for idb_metadata_resource
|
|
33
|
+
# ============================================================================
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@test()
|
|
37
|
+
def test_resource_idb_metadata():
|
|
38
|
+
"""idb_metadata_resource returns IDB metadata"""
|
|
39
|
+
result = idb_metadata_resource()
|
|
40
|
+
assert isinstance(result, dict)
|
|
41
|
+
assert_has_keys(result, "path", "module", "base", "size")
|
|
42
|
+
assert_non_empty(result["path"])
|
|
43
|
+
assert_valid_address(result["base"])
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# ============================================================================
|
|
47
|
+
# Tests for idb_segments_resource
|
|
48
|
+
# ============================================================================
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@test()
|
|
52
|
+
def test_resource_idb_segments():
|
|
53
|
+
"""idb_segments_resource returns segments list"""
|
|
54
|
+
result = idb_segments_resource()
|
|
55
|
+
assert isinstance(result, list)
|
|
56
|
+
if result:
|
|
57
|
+
assert_has_keys(result[0], "name", "start", "end")
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
# ============================================================================
|
|
61
|
+
# Tests for idb_entrypoints_resource
|
|
62
|
+
# ============================================================================
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@test()
|
|
66
|
+
def test_resource_idb_entrypoints():
|
|
67
|
+
"""idb_entrypoints_resource returns entry points"""
|
|
68
|
+
result = idb_entrypoints_resource()
|
|
69
|
+
assert isinstance(result, list)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
# ============================================================================
|
|
73
|
+
# Tests for cursor_resource
|
|
74
|
+
# ============================================================================
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@test()
|
|
78
|
+
def test_resource_cursor():
|
|
79
|
+
"""cursor_resource returns cursor info"""
|
|
80
|
+
try:
|
|
81
|
+
result = cursor_resource()
|
|
82
|
+
assert isinstance(result, dict)
|
|
83
|
+
# Should have addr key
|
|
84
|
+
assert_has_keys(result, "addr")
|
|
85
|
+
except IDAError:
|
|
86
|
+
pass # May fail in headless mode
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
# ============================================================================
|
|
90
|
+
# Tests for selection_resource
|
|
91
|
+
# ============================================================================
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
@test()
|
|
95
|
+
def test_resource_selection():
|
|
96
|
+
"""selection_resource returns selection info"""
|
|
97
|
+
try:
|
|
98
|
+
result = selection_resource()
|
|
99
|
+
assert isinstance(result, dict)
|
|
100
|
+
except IDAError:
|
|
101
|
+
pass # May fail in headless mode
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
# ============================================================================
|
|
105
|
+
# Tests for types_resource
|
|
106
|
+
# ============================================================================
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@test()
|
|
110
|
+
def test_resource_types():
|
|
111
|
+
"""types_resource returns local types"""
|
|
112
|
+
result = types_resource()
|
|
113
|
+
assert isinstance(result, list)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
# ============================================================================
|
|
117
|
+
# Tests for structs_resource
|
|
118
|
+
# ============================================================================
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
@test()
|
|
122
|
+
def test_resource_structs():
|
|
123
|
+
"""structs_resource returns structures list"""
|
|
124
|
+
result = structs_resource()
|
|
125
|
+
assert isinstance(result, list)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
# ============================================================================
|
|
129
|
+
# Tests for struct_name_resource
|
|
130
|
+
# ============================================================================
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
@test()
|
|
134
|
+
def test_resource_struct_name():
|
|
135
|
+
"""struct_name_resource returns structure info"""
|
|
136
|
+
# Try to get a structure (may not exist)
|
|
137
|
+
try:
|
|
138
|
+
result = struct_name_resource("test")
|
|
139
|
+
assert isinstance(result, dict)
|
|
140
|
+
except IDAError:
|
|
141
|
+
pass # Structure may not exist
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
@test()
|
|
145
|
+
def test_resource_struct_name_not_found():
|
|
146
|
+
"""struct_name_resource handles non-existent structure"""
|
|
147
|
+
try:
|
|
148
|
+
result = struct_name_resource("NonExistentStruct12345")
|
|
149
|
+
# Should return error or empty
|
|
150
|
+
except IDAError:
|
|
151
|
+
pass # Expected for non-existent struct
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
# ============================================================================
|
|
155
|
+
# Tests for import_name_resource
|
|
156
|
+
# ============================================================================
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
@test()
|
|
160
|
+
def test_resource_import_name():
|
|
161
|
+
"""import_name_resource returns import info"""
|
|
162
|
+
# Try to get an import (name depends on binary)
|
|
163
|
+
try:
|
|
164
|
+
result = import_name_resource("printf")
|
|
165
|
+
assert isinstance(result, dict)
|
|
166
|
+
except IDAError:
|
|
167
|
+
pass # Import may not exist in this binary
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
# ============================================================================
|
|
171
|
+
# Tests for export_name_resource
|
|
172
|
+
# ============================================================================
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
@test()
|
|
176
|
+
def test_resource_export_name():
|
|
177
|
+
"""export_name_resource returns export info"""
|
|
178
|
+
# Try to get main
|
|
179
|
+
try:
|
|
180
|
+
result = export_name_resource("main")
|
|
181
|
+
assert isinstance(result, dict)
|
|
182
|
+
except IDAError:
|
|
183
|
+
pass # Export may not exist
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
# ============================================================================
|
|
187
|
+
# Tests for xrefs_from_resource
|
|
188
|
+
# ============================================================================
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
@test()
|
|
192
|
+
def test_resource_xrefs_from():
|
|
193
|
+
"""xrefs_from_resource returns cross-references"""
|
|
194
|
+
fn_addr = get_any_function()
|
|
195
|
+
if not fn_addr:
|
|
196
|
+
return
|
|
197
|
+
|
|
198
|
+
result = xrefs_from_resource(fn_addr)
|
|
199
|
+
assert isinstance(result, list)
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""Tests for api_stack API functions."""
|
|
2
|
+
|
|
3
|
+
# Import test framework from parent
|
|
4
|
+
from ..framework import (
|
|
5
|
+
test,
|
|
6
|
+
assert_has_keys,
|
|
7
|
+
assert_is_list,
|
|
8
|
+
get_any_function,
|
|
9
|
+
get_data_address,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
# Import functions under test
|
|
13
|
+
from ..api_stack import (
|
|
14
|
+
stack_frame,
|
|
15
|
+
declare_stack,
|
|
16
|
+
delete_stack,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
# Import sync module for IDAError
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# ============================================================================
|
|
23
|
+
# Tests for stack_frame
|
|
24
|
+
# ============================================================================
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@test()
|
|
28
|
+
def test_stack_frame():
|
|
29
|
+
"""stack_frame returns stack frame info for a function"""
|
|
30
|
+
fn_addr = get_any_function()
|
|
31
|
+
if not fn_addr:
|
|
32
|
+
return
|
|
33
|
+
|
|
34
|
+
result = stack_frame(fn_addr)
|
|
35
|
+
assert_is_list(result, min_length=1)
|
|
36
|
+
r = result[0]
|
|
37
|
+
assert_has_keys(r, "addr", "frame", "error")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@test()
|
|
41
|
+
def test_stack_frame_no_function():
|
|
42
|
+
"""stack_frame handles non-function address"""
|
|
43
|
+
data_addr = get_data_address()
|
|
44
|
+
if not data_addr:
|
|
45
|
+
return
|
|
46
|
+
|
|
47
|
+
result = stack_frame(data_addr)
|
|
48
|
+
assert_is_list(result, min_length=1)
|
|
49
|
+
r = result[0]
|
|
50
|
+
# Should have error or null frame
|
|
51
|
+
assert r.get("error") is not None or r.get("frame") is None
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
# ============================================================================
|
|
55
|
+
# Tests for declare_stack / delete_stack
|
|
56
|
+
# ============================================================================
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@test(skip=True) # Skip by default as it modifies the database
|
|
60
|
+
def test_declare_delete_stack():
|
|
61
|
+
"""declare_stack and delete_stack work together"""
|
|
62
|
+
fn_addr = get_any_function()
|
|
63
|
+
if not fn_addr:
|
|
64
|
+
return
|
|
65
|
+
|
|
66
|
+
# Try to declare a stack variable
|
|
67
|
+
result = declare_stack(
|
|
68
|
+
{"func": fn_addr, "name": "__test_var__", "offset": -8, "type": "int"}
|
|
69
|
+
)
|
|
70
|
+
assert_is_list(result, min_length=1)
|
|
71
|
+
r = result[0]
|
|
72
|
+
assert_has_keys(r, "func", "error")
|
|
73
|
+
|
|
74
|
+
# If declare succeeded, try to delete
|
|
75
|
+
if r.get("error") is None:
|
|
76
|
+
del_result = delete_stack({"func": fn_addr, "name": "__test_var__"})
|
|
77
|
+
assert_is_list(del_result, min_length=1)
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
"""Tests for api_types API functions."""
|
|
2
|
+
|
|
3
|
+
# Import test framework from parent
|
|
4
|
+
from ..framework import (
|
|
5
|
+
test,
|
|
6
|
+
assert_has_keys,
|
|
7
|
+
assert_is_list,
|
|
8
|
+
get_any_function,
|
|
9
|
+
get_first_segment,
|
|
10
|
+
get_data_address,
|
|
11
|
+
get_unmapped_address,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
# Import functions under test
|
|
15
|
+
from ..api_types import (
|
|
16
|
+
declare_type,
|
|
17
|
+
read_struct,
|
|
18
|
+
search_structs,
|
|
19
|
+
set_type,
|
|
20
|
+
infer_types,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
# Import sync module for IDAError
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# ============================================================================
|
|
27
|
+
# Test Helpers
|
|
28
|
+
# ============================================================================
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def create_test_struct(name: str = "__TestStruct__") -> bool:
|
|
32
|
+
"""Helper to create a test struct in IDA's type library.
|
|
33
|
+
|
|
34
|
+
This function is idempotent - if the struct already exists, it will return True.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
name: Name of the struct to create
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
True if struct exists or was created successfully, False otherwise
|
|
41
|
+
"""
|
|
42
|
+
# First check if struct already exists
|
|
43
|
+
search_result = search_structs(name)
|
|
44
|
+
if search_result and any(s["name"] == name for s in search_result):
|
|
45
|
+
return True # Already exists
|
|
46
|
+
|
|
47
|
+
# Struct doesn't exist, try to create it
|
|
48
|
+
struct_def = f"""
|
|
49
|
+
struct {name} {{
|
|
50
|
+
int field1;
|
|
51
|
+
char field2;
|
|
52
|
+
void* field3;
|
|
53
|
+
}};
|
|
54
|
+
"""
|
|
55
|
+
result = declare_type(struct_def)
|
|
56
|
+
if not result:
|
|
57
|
+
return False
|
|
58
|
+
|
|
59
|
+
# Check if declaration succeeded
|
|
60
|
+
r = result[0]
|
|
61
|
+
if r.get("ok"):
|
|
62
|
+
return True
|
|
63
|
+
|
|
64
|
+
# Check if it failed because it already exists
|
|
65
|
+
if r.get("error"):
|
|
66
|
+
# Search again to see if it exists despite the error
|
|
67
|
+
search_result = search_structs(name)
|
|
68
|
+
return search_result and any(s["name"] == name for s in search_result)
|
|
69
|
+
|
|
70
|
+
return False
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
# ============================================================================
|
|
74
|
+
# Tests for declare_type
|
|
75
|
+
# ============================================================================
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@test()
|
|
79
|
+
def test_declare_type():
|
|
80
|
+
"""declare_type can add a type declaration"""
|
|
81
|
+
# Try to declare a simple struct
|
|
82
|
+
result = declare_type("struct __test_struct__ { int x; };")
|
|
83
|
+
assert_is_list(result, min_length=1)
|
|
84
|
+
r = result[0]
|
|
85
|
+
assert_has_keys(r, "decl")
|
|
86
|
+
# Should succeed without error
|
|
87
|
+
assert r.get("ok") is not None or r.get("error") is None
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
# ============================================================================
|
|
91
|
+
# Tests for read_struct
|
|
92
|
+
# ============================================================================
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@test()
|
|
96
|
+
def test_read_struct():
|
|
97
|
+
"""read_struct reads structure at address"""
|
|
98
|
+
data_addr = get_data_address()
|
|
99
|
+
if not data_addr:
|
|
100
|
+
seg = get_first_segment()
|
|
101
|
+
if not seg:
|
|
102
|
+
return
|
|
103
|
+
data_addr = seg[0]
|
|
104
|
+
|
|
105
|
+
result = read_struct({"addr": data_addr, "struct": "test_struct"})
|
|
106
|
+
assert_is_list(result, min_length=1)
|
|
107
|
+
r = result[0]
|
|
108
|
+
# Should have addr, struct, and either members or error
|
|
109
|
+
assert_has_keys(r, "addr", "struct")
|
|
110
|
+
assert r.get("members") is not None or r.get("error") is not None
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@test()
|
|
114
|
+
def test_read_struct_not_found():
|
|
115
|
+
"""read_struct handles non-existent struct"""
|
|
116
|
+
seg = get_first_segment()
|
|
117
|
+
if not seg:
|
|
118
|
+
return
|
|
119
|
+
|
|
120
|
+
result = read_struct({"addr": seg[0], "struct": "NonExistentStruct12345"})
|
|
121
|
+
assert_is_list(result, min_length=1)
|
|
122
|
+
r = result[0]
|
|
123
|
+
# Should have error
|
|
124
|
+
assert r.get("error") is not None
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
@test()
|
|
128
|
+
def test_read_struct_name_resolution():
|
|
129
|
+
"""read_struct can resolve named addresses (e.g., function names)"""
|
|
130
|
+
# Create a test struct first
|
|
131
|
+
if not create_test_struct("__NameResolutionTest__"):
|
|
132
|
+
return
|
|
133
|
+
|
|
134
|
+
fn_addr = get_any_function()
|
|
135
|
+
if not fn_addr:
|
|
136
|
+
return
|
|
137
|
+
|
|
138
|
+
# Get the function name
|
|
139
|
+
from ..api_core import lookup_funcs
|
|
140
|
+
|
|
141
|
+
fn_info = lookup_funcs(fn_addr)
|
|
142
|
+
if not fn_info or not fn_info[0].get("fn"):
|
|
143
|
+
return
|
|
144
|
+
|
|
145
|
+
fn_name = fn_info[0]["fn"]["name"]
|
|
146
|
+
|
|
147
|
+
# Use the function name as address (should resolve via get_name_ea)
|
|
148
|
+
result = read_struct({"addr": fn_name, "struct": "__NameResolutionTest__"})
|
|
149
|
+
assert_is_list(result, min_length=1)
|
|
150
|
+
r = result[0]
|
|
151
|
+
# Should either succeed with members or have a specific error
|
|
152
|
+
# (not a "Failed to resolve address" error)
|
|
153
|
+
if r.get("error"):
|
|
154
|
+
# If there's an error, it should be about the struct, not address resolution
|
|
155
|
+
assert "Failed to resolve address" not in r["error"]
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
@test()
|
|
159
|
+
def test_read_struct_invalid_address():
|
|
160
|
+
"""read_struct handles invalid address gracefully"""
|
|
161
|
+
result = read_struct(
|
|
162
|
+
{"addr": "InvalidAddressName123", "struct": "NonExistentStruct"}
|
|
163
|
+
)
|
|
164
|
+
assert_is_list(result, min_length=1)
|
|
165
|
+
r = result[0]
|
|
166
|
+
# Should have error about failed address resolution
|
|
167
|
+
assert r.get("error") is not None
|
|
168
|
+
assert "Failed to resolve address" in r["error"]
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
# ============================================================================
|
|
172
|
+
# Tests for search_structs
|
|
173
|
+
# ============================================================================
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
@test()
|
|
177
|
+
def test_search_structs():
|
|
178
|
+
"""search_structs can search for structures"""
|
|
179
|
+
result = search_structs("*")
|
|
180
|
+
assert_is_list(result)
|
|
181
|
+
# Check result structure if any structs exist
|
|
182
|
+
if len(result) > 0:
|
|
183
|
+
r = result[0]
|
|
184
|
+
assert_has_keys(r, "name", "size", "cardinality", "is_union", "ordinal")
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
@test()
|
|
188
|
+
def test_search_structs_pattern():
|
|
189
|
+
"""search_structs can filter by pattern"""
|
|
190
|
+
# Test with a pattern that likely won't match anything
|
|
191
|
+
result = search_structs("VeryUnlikelyStructName123*")
|
|
192
|
+
assert_is_list(result)
|
|
193
|
+
# Should return empty list
|
|
194
|
+
assert len(result) == 0
|
|
195
|
+
|
|
196
|
+
# Test with wildcard that should match everything
|
|
197
|
+
result_all = search_structs("*")
|
|
198
|
+
assert_is_list(result_all)
|
|
199
|
+
# Wildcard should return at least as many results as specific pattern
|
|
200
|
+
assert len(result_all) >= len(result)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
# ============================================================================
|
|
204
|
+
# Tests for set_type
|
|
205
|
+
# ============================================================================
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
@test()
|
|
209
|
+
def test_set_type():
|
|
210
|
+
"""set_type applies type to address"""
|
|
211
|
+
fn_addr = get_any_function()
|
|
212
|
+
if not fn_addr:
|
|
213
|
+
return
|
|
214
|
+
|
|
215
|
+
result = set_type({"addr": fn_addr, "ty": "int"})
|
|
216
|
+
assert_is_list(result, min_length=1)
|
|
217
|
+
r = result[0]
|
|
218
|
+
# Result has "edit" key containing the input, and optionally "ok" or "error"
|
|
219
|
+
assert_has_keys(r, "edit")
|
|
220
|
+
assert r.get("ok") is not None or r.get("error") is not None
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
@test()
|
|
224
|
+
def test_set_type_invalid_address():
|
|
225
|
+
"""set_type handles invalid address"""
|
|
226
|
+
result = set_type({"addr": get_unmapped_address(), "ty": "int"})
|
|
227
|
+
assert_is_list(result, min_length=1)
|
|
228
|
+
r = result[0]
|
|
229
|
+
# Should have "edit" key and either "ok" or "error"
|
|
230
|
+
assert_has_keys(r, "edit")
|
|
231
|
+
assert r.get("ok") is not None or r.get("error") is not None
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
# ============================================================================
|
|
235
|
+
# Tests for infer_types
|
|
236
|
+
# ============================================================================
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
@test()
|
|
240
|
+
def test_infer_types():
|
|
241
|
+
"""infer_types infers types for a function"""
|
|
242
|
+
fn_addr = get_any_function()
|
|
243
|
+
if not fn_addr:
|
|
244
|
+
return
|
|
245
|
+
|
|
246
|
+
result = infer_types(fn_addr)
|
|
247
|
+
assert_is_list(result, min_length=1)
|
|
248
|
+
r = result[0]
|
|
249
|
+
assert_has_keys(r, "addr", "error")
|