Skip to content

Commit ec6f14e

Browse files
committed
dev: signatures done
1 parent f0880bd commit ec6f14e

6 files changed

Lines changed: 114 additions & 104 deletions

File tree

revengai/features/match_current_function/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ def __init__(self, config=None):
1111

1212
def register(self):
1313
PluginCommand.register_for_address(
14-
"RevEng.AI\\Match Current Function",
14+
"RevEng.AI\\6 - Match Current Function",
1515
"Search and match the current function against RevEng.AI database",
1616
self.show_match_current_function_dialog,
1717
self.is_valid

revengai/features/match_current_function/match_current_function.py

Lines changed: 82 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -342,104 +342,100 @@ def rename_function(self, bv: BinaryView, selected_result: Dict) -> List[Dict]:
342342

343343
def _process_data_type_batch(self, chunk: List[Dict]) -> List[Dict]:
344344
try:
345-
log_info(f"RevEng.AI | Processing data types batch of {len(chunk)} items")
346-
347-
nearest_neighbor_ids = [item["nearest_neighbor_id"] for item in chunk]
348-
349-
response = RE_functions_data_types(nearest_neighbor_ids)
350-
351-
if response.status_code != 200:
352-
log_error(f"RevEng.AI | Data types API call failed with status {response.status_code}")
353-
return []
354-
355-
data = response.json()
356-
357-
if "status" in data and data["status"] == "processing":
358-
poll_id = data.get("poll_id")
359-
if poll_id:
360-
log_info(f"RevEng.AI | Polling for data types with ID: {poll_id}")
361-
362-
max_attempts = 30
363-
for attempt in range(max_attempts):
364-
time.sleep(2)
365-
poll_response = RE_functions_data_types_poll(poll_id)
366-
367-
if poll_response.status_code == 200:
368-
poll_data = poll_response.json()
369-
if poll_data.get("status") == "completed":
370-
data = poll_data
371-
break
372-
else:
373-
log_error(f"RevEng.AI | Polling failed with status {poll_response.status_code}")
374-
break
375-
else:
376-
log_error(f"RevEng.AI | Polling timed out after {max_attempts} attempts")
377-
return []
378-
345+
log_info(f"RevEng.AI | Processing chunk of {len(chunk)} functions")
346+
function_ids = set([result['nearest_neighbor_id'] for result in chunk])
347+
RE_functions_data_types(function_ids=list(function_ids))
379348
signatures = []
380-
for item in data.get("data", []):
381-
signature = self.make_signature(item.get("data_types", []))
382-
signatures.append({
383-
"nearest_neighbor_id": item["nearest_neighbor_id"],
384-
"signature": signature
385-
})
386-
349+
items = []
350+
while True:
351+
response = RE_functions_data_types_poll(
352+
function_ids=list(function_ids),
353+
).json()
354+
data = response.get("data", {})
355+
items = data.get("items", [])
356+
357+
pending_count = sum(1 for item in items if item.get("status") == "pending")
358+
log_info(f"RevEng.AI | {pending_count} items still pending... trying again")
359+
if not pending_count:
360+
break
361+
time.sleep(3)
362+
363+
for item in items:
364+
log_info(f"RevEng.AI | Item: {item['function_id']}")
365+
if item['status'] != "completed":
366+
continue
367+
for result in chunk:
368+
if result['nearest_neighbor_id'] == item['function_id']:
369+
signature = self.make_signature(item['data_types'])
370+
if signature != "N/A":
371+
signatures.append({"nearest_neighbor_id": result['nearest_neighbor_id'], "signature": signature})
372+
break
373+
374+
#log_info(f"RevEng.AI | Total count: {total_count}")
375+
#log_info(f"RevEng.AI | Total data types: {total_data_types}")
376+
#log_info(f"RevEng.AI | Items: {items}")
377+
387378
return signatures
388-
389379
except Exception as e:
390-
log_error(f"RevEng.AI | Error processing data types batch: {str(e)}")
380+
log_error(f"RevEng.AI | Error processing data type batch: {str(e)}")
391381
return []
392-
382+
393383
def make_signature(self, data_types: List[Dict]) -> str:
394384
try:
395-
if not data_types:
396-
return "void function();"
397-
398-
# For now, create a simple signature
399-
# This would need to be enhanced based on actual data_types structure
400-
return_type = "void"
401-
params = []
402-
403-
for dt in data_types:
404-
if dt.get("type") == "return":
405-
return_type = dt.get("name", "void")
406-
elif dt.get("type") == "parameter":
407-
param_type = dt.get("name", "int")
408-
param_name = dt.get("param_name", f"param{len(params)}")
409-
params.append(f"{param_type} {param_name}")
410-
411-
params_str = ", ".join(params) if params else ""
412-
return f"{return_type} function({params_str});"
413-
385+
#log_info(f"RevEng.AI | Making signature for {data_types}")
386+
signature = "("
387+
for _, arg in data_types['func_types'].get('header', {}).get('args', {}).items():
388+
#log_info(f"RevEng.AI | Arg: {arg}")
389+
signature += f"{arg.get('type', 'N/A')}, "
390+
signature = signature[:-2] if signature.endswith(", ") else signature
391+
392+
signature += f") {data_types['func_types'].get('type', 'N/A')}"
393+
394+
log_info(f"RevEng.AI | Signature: {signature}")
395+
return signature
414396
except Exception as e:
415-
log_error(f"RevEng.AI | Error creating signature: {str(e)}")
416-
return "void function();"
397+
log_error(f"RevEng.AI | Error making signature: {str(e)}")
398+
return "N/A"
417399

418400
def fetch_data_types(self, bv: BinaryView, selected_results: List[Dict]) -> Tuple[bool, Dict[str, Any]]:
419-
"""Fetch data types for selected function matches"""
420401
try:
421-
log_info(f"RevEng.AI | Starting data type fetching for {len(selected_results)} functions")
402+
log_info("RevEng.AI | Starting data type fetching")
422403

423-
# Process in chunks to avoid API limits
404+
if len(selected_results) == 0:
405+
return False, "No valid functions selected"
406+
424407
chunk_size = 50
425-
all_signatures = []
426-
427-
for i in range(0, len(selected_results), chunk_size):
428-
chunk = selected_results[i:i+chunk_size]
429-
log_info(f"RevEng.AI | Processing chunk {i//chunk_size + 1}/{(len(selected_results) + chunk_size - 1)//chunk_size}")
430-
431-
signatures = self._process_data_type_batch(chunk)
432-
all_signatures.extend(signatures)
433-
434-
success_count = len([s for s in all_signatures if s.get("signature") != "void function();"])
435-
436-
log_info(f"RevEng.AI | Data type fetching completed. {success_count} functions have signatures")
408+
if len(selected_results) < chunk_size:
409+
chunks = [selected_results]
410+
else:
411+
chunks = [selected_results[i:i + chunk_size] for i in range(0, len(selected_results), chunk_size)]
412+
413+
log_info(f"RevEng.AI | Processing {len(selected_results)} functions in {len(chunks)} chunks of size {chunk_size}")
414+
415+
signatures = []
437416

438-
return True, {
439-
"signatures": all_signatures,
440-
"success_count": success_count
417+
with ThreadPoolExecutor(max_workers=4) as executor:
418+
future_to_chunk = {
419+
executor.submit(self._process_data_type_batch, chunk): i
420+
for i, chunk in enumerate(chunks)
421+
}
422+
423+
for future in as_completed(future_to_chunk):
424+
chunk_index = future_to_chunk[future]
425+
try:
426+
chunk = future.result()
427+
log_info(f"RevEng.AI | Chunk {chunk_index} completed")
428+
signatures.extend(chunk)
429+
430+
except Exception as e:
431+
log_error(f"RevEng.AI | Error processing chunk {chunk_index}: {str(e)}")
432+
433+
options = {
434+
"success_count": len(signatures),
435+
"signatures": signatures
441436
}
442-
437+
438+
return True, options
443439
except Exception as e:
444-
log_error(f"RevEng.AI | Error in data type fetching: {str(e)}")
445-
return False, str(e)
440+
log_error(f"RevEng.AI | Error fetching data types: {str(e)}")
441+
return False, str(e)

revengai/features/match_current_function/match_current_function_dialog.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ def on_fetching_data_types_finished(self, success, data):
305305
if success:
306306
log_info(f"RevEng.AI | Data type fetching completed with {data['success_count']} functions having signatures")
307307
self.results_tab.update_current_matches_with_signatures(data["signatures"])
308-
self.results_tab.populate_results_table()
308+
#self.results_tab.populate_results_table()
309309
self.status_label.setText(f"Data type fetching completed: {data['success_count']} functions have signatures")
310310

311311
QMessageBox.information(

revengai/features/match_functions/match_functions.py

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -371,31 +371,33 @@ def _process_data_type_batch(self, chunk: List[Dict]) -> List[Dict]:
371371
function_ids = set([result['nearest_neighbor_id'] for result in chunk])
372372
RE_functions_data_types(function_ids=list(function_ids))
373373
signatures = []
374+
items = []
374375
while True:
375376
response = RE_functions_data_types_poll(
376377
function_ids=list(function_ids),
377378
).json()
378379
data = response.get("data", {})
379-
total_count = data.get("total_count", 0)
380-
total_data_types = data.get("total_data_types_count", 0)
381380
items = data.get("items", [])
382-
log_info(f"RevEng.AI | Response: {response}")
383-
if not any(item.get("status") == "pending" for item in items):
381+
pending_count = sum(1 for item in items if item.get("status") == "pending")
382+
log_info(f"RevEng.AI | {pending_count} items still pending... trying again")
383+
if not pending_count:
384384
break
385385
time.sleep(3)
386386

387387
for item in items:
388388
log_info(f"RevEng.AI | Item: {item['function_id']}")
389+
if item['status'] != "completed":
390+
continue
389391
for result in chunk:
390392
if result['nearest_neighbor_id'] == item['function_id']:
391393
signature = self.make_signature(item['data_types'])
392394
if signature != "N/A":
393395
signatures.append({"nearest_neighbor_id": result['nearest_neighbor_id'], "signature": signature})
394396
break
395397

396-
log_info(f"RevEng.AI | Total count: {total_count}")
397-
log_info(f"RevEng.AI | Total data types: {total_data_types}")
398-
log_info(f"RevEng.AI | Items: {items}")
398+
#log_info(f"RevEng.AI | Total count: {total_count}")
399+
#log_info(f"RevEng.AI | Total data types: {total_data_types}")
400+
#log_info(f"RevEng.AI | Items: {items}")
399401

400402
return signatures
401403
except Exception as e:
@@ -404,12 +406,14 @@ def _process_data_type_batch(self, chunk: List[Dict]) -> List[Dict]:
404406

405407
def make_signature(self, data_types: List[Dict]) -> str:
406408
try:
407-
log_info(f"RevEng.AI | Making signature for {data_types}")
408-
signature = ""
409-
signature += f"{data_types['func_types'].get('type', 'N/A')} "
410-
411-
for arg in data_types['func_types'].get('args', []):
409+
#log_info(f"RevEng.AI | Making signature for {data_types}")
410+
signature = "("
411+
for _, arg in data_types['func_types'].get('header', {}).get('args', {}).items():
412+
#log_info(f"RevEng.AI | Arg: {arg}")
412413
signature += f"{arg.get('type', 'N/A')}, "
414+
signature = signature[:-2] if signature.endswith(", ") else signature
415+
416+
signature += f") {data_types['func_types'].get('type', 'N/A')}"
413417

414418
log_info(f"RevEng.AI | Signature: {signature}")
415419
return signature
@@ -425,7 +429,10 @@ def fetch_data_types(self, bv: BinaryView, selected_results: List[Dict]) -> Tupl
425429
return False, "No valid functions selected"
426430

427431
chunk_size = 50
428-
chunks = [selected_results[i:i + chunk_size] for i in range(0, len(selected_results), chunk_size)]
432+
if len(selected_results) < chunk_size:
433+
chunks = [selected_results]
434+
else:
435+
chunks = [selected_results[i:i + chunk_size] for i in range(0, len(selected_results), chunk_size)]
429436

430437
log_info(f"RevEng.AI | Processing {len(selected_results)} functions in {len(chunks)} chunks of size {chunk_size}")
431438

revengai/features/match_functions/match_functions_dialog.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ def on_fetching_data_types_finished(self, success, data):
230230
if success:
231231
log_info(f"RevEng.AI | Data type fetching completed with {data['success_count']} functions having signatures")
232232
self.results_tab.update_current_matches_with_signatures(data["signatures"])
233-
self.results_tab.populate_results_table()
233+
#self.results_tab.populate_results_table()
234234
self.status_label.setText(f"Data type fetching completed!")
235235
self.results_tab.status_label.setText(f"Data type fetching completed: {data['success_count']} functions have signatures")
236236
QMessageBox.information(self, "RevEng.AI Fetch Data Types", f"Data types fetched successfully.\n{data['success_count']} function{'' if data['success_count'] == 1 else 's'} have signatures.", QMessageBox.Ok)

revengai/features/match_functions/tab_result.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ def filter_results(self, text):
7171
def populate_results_table(self):
7272
self.selected_results.clear()
7373

74+
self.results_table.setRowCount(0)
7475
self.results_table.setRowCount(len(self.current_matches))
7576

7677
for row, match in enumerate(self.current_matches):
@@ -94,19 +95,25 @@ def populate_results_table(self):
9495

9596
for column, field in enumerate(column_data, start=1):
9697
value = match.get(field, "N/A")
97-
item = QTableWidgetItem(value if len(value) < 25 else value[:22] + "...")
98+
if field != "signature":
99+
value = value if len(value) < 25 else value[:22] + "..."
100+
item = QTableWidgetItem(value)
98101
item.setFlags(item.flags() & ~Qt.ItemIsEditable)
99102
self.results_table.setItem(row, column, item)
100103

101104
if icon_text == "Success":
102105
self.selected_results.append(match)
103106

104107
def update_current_matches_with_signatures(self, selected_results):
108+
log_info(f"RevEng.AI | Updating current matches with signatures")
105109
for match in self.current_matches:
106-
if match.get("nearest_neighbor_id", False):
110+
if not match.get("nearest_neighbor_id", False):
107111
continue
108112
for result in selected_results:
113+
if not result.get("nearest_neighbor_id", False):
114+
continue
109115
if match["nearest_neighbor_id"] == result["nearest_neighbor_id"]:
116+
log_info(f"RevEng.AI | Found signature for {match['original_name']}")
110117
match["signature"] = result["signature"]
111118
break
112119
self.populate_results_table()

0 commit comments

Comments
 (0)