include basic block matches in capabilities by function table

This commit is contained in:
Soufiane Fariss
2024-07-29 17:02:54 +02:00
parent 38cf1f1041
commit 13261d0c41
2 changed files with 86 additions and 69 deletions
+5 -21
View File
@@ -7,7 +7,6 @@
sortMode="single"
removableSort
size="small"
:sortOrder="1"
:filters="filters"
:rowHover="true"
:filterMode="filterMode"
@@ -20,14 +19,14 @@
<Column field="funcaddr" sortable header="Function Address" :rowspan="3" class="w-min">
<template #body="slotProps">
{{ slotProps.data.funcaddr }}
<span v-if="slotProps.data.matchcount > 1" class="font-italic">
({{ slotProps.data.matchcount }} matches)
<span style="font-family: monospace">{{ slotProps.data.funcaddr }}</span>
<span v-if="slotProps.data.matchCount > 1" class="font-italic">
({{ slotProps.data.matchCount }} matches)
</span>
</template>
</Column>
<Column field="ruleName" sortable header="Matches" class="w-min">
<Column field="ruleName" header="Matches" class="w-min">
<template #body="slotProps">
{{ slotProps.data.ruleName }}
<LibraryTag
@@ -36,21 +35,7 @@
</template>
</Column>
<Column field="namespace" sortable header="Namespace"></Column>
<Column field="source" header="Source">
<template #body="slotProps">
<Button
v-if="slotProps.data.source"
rounded
icon="pi pi-external-link"
size="small"
severity="secondary"
style="height: 1.5rem; width: 1.5rem"
@click="showSource(slotProps.data.source)"
/>
</template>
</Column>
<Column field="namespace" header="Namespace"></Column>
</DataTable>
<Dialog v-model:visible="sourceDialogVisible" :style="{ width: '50vw' }">
@@ -64,7 +49,6 @@ import { ref, computed } from 'vue'
import DataTable from 'primevue/datatable'
import Column from 'primevue/column'
import Dialog from 'primevue/dialog'
import Button from 'primevue/button'
import LibraryTag from './misc/LibraryTag.vue'
import InputText from 'primevue/inputtext'
+81 -48
View File
@@ -75,55 +75,91 @@ export function parseRules(rules, flavor) {
*/
export function parseFunctionCapabilities(data, showLibraryRules) {
const result = [];
let id = 0;
const matchesByFunction = new Map();
// Iterate through each function in the metadata
for (const functionInfo of data.meta.analysis.layout.functions) {
// Convert function address to uppercase hexadecimal string
const functionAddress = functionInfo.address.value.toString(16).toUpperCase();
const matchingRules = [];
// Iterate through all rules in the data
for (const ruleId in data.rules) {
const rule = data.rules[ruleId];
// Skip library rules if showLibraryRules is false
if (!showLibraryRules && rule.meta.lib) {
continue;
}
// Find matches for this rule within the current function
const matches = rule.matches.filter((match) =>
// Check if any of the function's basic blocks match the rule
functionInfo.matched_basic_blocks.some((block) => block.address.value === match[0].value)
);
// If there are matches, add this rule to the matchingRules array
if (matches.length > 0) {
matchingRules.push({
ruleName: rule.meta.name,
lib: rule.meta.lib,
namespace: rule.meta.namespace,
source: rule.source
});
}
}
// If there are matching rules for this function, add it to the result
if (matchingRules.length > 0) {
// Add each matching rule as a separate row
matchingRules.forEach(rule => {
result.push({
id: id++,
funcaddr: `0x${functionAddress}`,
matchcount: matchingRules.length,
...rule
});
});
// Create a map of basic blocks to functions
const functionsByBB = new Map();
for (const func of data.meta.analysis.layout.functions) {
const funcAddress = func.address.value;
for (const bb of func.matched_basic_blocks) {
functionsByBB.set(bb.address.value, funcAddress);
}
}
return result;
// Iterate through all rules in the data
for (const ruleId in data.rules) {
const rule = data.rules[ruleId];
// Skip library rules if showLibraryRules is false
if (!showLibraryRules && rule.meta.lib) {
continue;
}
if (rule.meta.scopes.static === 'function') {
// Function scope
for (const [addr] of rule.matches) {
const funcAddr = addr.value;
if (!matchesByFunction.has(funcAddr)) {
matchesByFunction.set(funcAddr, new Map());
}
const funcMatches = matchesByFunction.get(funcAddr);
funcMatches.set(rule.meta.name, {
count: (funcMatches.get(rule.meta.name)?.count || 0) + 1,
namespace: rule.meta.namespace,
lib: rule.meta.lib
});
}
} else if (rule.meta.scopes.static === 'basic block') {
// Basic block scope
for (const [addr] of rule.matches) {
const bbAddr = addr.value;
const funcAddr = functionsByBB.get(bbAddr);
if (funcAddr) {
if (!matchesByFunction.has(funcAddr)) {
matchesByFunction.set(funcAddr, new Map());
}
const funcMatches = matchesByFunction.get(funcAddr);
funcMatches.set(rule.meta.name, {
count: (funcMatches.get(rule.meta.name)?.count || 0) + 1,
namespace: rule.meta.namespace,
lib: rule.meta.lib
});
}
}
}
}
// Convert the matchesByFunction map to the intermediate result array
for (const [funcAddr, matches] of matchesByFunction) {
const functionAddress = funcAddr.toString(16).toUpperCase();
const matchingRules = Array.from(matches, ([ruleName, data]) => ({
ruleName,
matchCount: data.count,
namespace: data.namespace,
lib: data.lib
}));
result.push({
funcaddr: `0x${functionAddress}`,
matchCount: matchingRules.length,
capabilities: matchingRules,
lib: data.lib
});
}
// Transform the intermediate result into the final format
const finalResult = result.flatMap(func =>
func.capabilities.map(cap => ({
funcaddr: func.funcaddr,
matchCount: func.matchCount,
ruleName: cap.ruleName,
ruleMatchCount: cap.matchCount,
namespace: cap.namespace,
lib: cap.lib,
}))
);
return finalResult;
}
/**
@@ -436,9 +472,6 @@ function getRangeName(statement) {
function getNodeAddress(node) {
if (node.node.feature && node.node.feature.type === 'regex') return null
if (node.locations && node.locations.length > 0) {
// for example: 0x400000
//return `0x${node.locations[0].value.toString(16).toUpperCase()}`
console.log(node.locations[0])
return formatAddress(node.locations[0]);
}
return null