Skip to content

Commit 80b450b

Browse files
authored
patch: enable patch interface to pass reference of objects for patch function to mutate the state
* Add is_reference field to identify if arguments passed as reference
1 parent 9692606 commit 80b450b

8 files changed

Lines changed: 526 additions & 280 deletions

File tree

docs/GettingStarted/patch_specifications.md

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ meta_patches: # Meta-patch configurations
7878
- name: "..."
7979
source: "..."
8080
index: "0"
81+
is_reference=true
8182

8283
meta_contracts: # Meta-contract configurations
8384
- name: ...
@@ -390,10 +391,6 @@ meta_patches:
390391
source: "variable"
391392
symbol: "var1"
392393
393-
exclude:
394-
- "test_*"
395-
- "debug_*"
396-
397394
meta_contracts:
398395
- name: usb_security_meta_contracts
399396
description: "Meta contracts for USB security validation"

include/patchestry/Passes/InstrumentationPass.hpp

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ namespace patchestry::passes { // NOLINT
189189
*/
190190
void prepare_call_arguments(
191191
mlir::OpBuilder &builder, mlir::Operation *op, cir::FuncOp patch_func,
192-
const PatchInformation &patch, llvm::SmallVector< mlir::Value > &args
192+
const PatchInformation &patch, llvm::DenseMap< mlir::Value, mlir::Value > &args_map
193193
);
194194

195195
/**
@@ -293,6 +293,82 @@ namespace patchestry::passes { // NOLINT
293293
* @param target_op The original operation being instrumented
294294
*/
295295
void set_patch_call_attributes(cir::CallOp patch_call_op, mlir::Operation *target_op);
296+
297+
/**
298+
* @brief Creates a cast operation if types differ, otherwise returns the original
299+
* value.
300+
*/
301+
mlir::Value create_cast_if_needed(
302+
mlir::OpBuilder &builder, mlir::Operation *call_op, mlir::Value value,
303+
mlir::Type target_type
304+
);
305+
306+
/**
307+
* @brief Creates a reference (alloca + store) for a given value.
308+
*/
309+
mlir::Value
310+
create_reference(mlir::OpBuilder &builder, mlir::Operation *call_op, mlir::Value value);
311+
312+
/**
313+
* @brief Handles OPERAND argument source type.
314+
*/
315+
void handle_operand_argument(
316+
mlir::OpBuilder &builder, mlir::Operation *call_op, const ArgumentSource &arg_spec,
317+
mlir::Type patch_arg_type, llvm::DenseMap< mlir::Value, mlir::Value > &arg_map
318+
);
319+
320+
/**
321+
* @brief Handles VARIABLE argument source type.
322+
*/
323+
void handle_variable_argument(
324+
mlir::OpBuilder &builder, mlir::Operation *call_op, const ArgumentSource &arg_spec,
325+
mlir::Type patch_arg_type, llvm::DenseMap< mlir::Value, mlir::Value > &arg_map
326+
);
327+
328+
/**
329+
* @brief Handles SYMBOL argument source type.
330+
*/
331+
void handle_symbol_argument(
332+
mlir::OpBuilder &builder, mlir::Operation *call_op, const ArgumentSource &arg_spec,
333+
mlir::Type patch_arg_type, llvm::DenseMap< mlir::Value, mlir::Value > &arg_map
334+
);
335+
336+
/**
337+
* @brief Handles RETURN_VALUE argument source type.
338+
*/
339+
void handle_return_value_argument(
340+
mlir::OpBuilder &builder, mlir::Operation *call_op, const ArgumentSource &arg_spec,
341+
mlir::Type patch_arg_type, llvm::DenseMap< mlir::Value, mlir::Value > &arg_map
342+
);
343+
344+
/**
345+
* @brief Handles CONSTANT argument source type.
346+
*/
347+
void handle_constant_argument(
348+
mlir::OpBuilder &builder, mlir::Operation *call_op, const ArgumentSource &arg_spec,
349+
mlir::Type patch_arg_type, llvm::DenseMap< mlir::Value, mlir::Value > &arg_map
350+
);
351+
352+
/**
353+
* @brief Parses a constant operand from string based on the target type.
354+
*/
355+
mlir::Value parse_constant_operand(
356+
mlir::OpBuilder &builder, mlir::Operation *call_op, const std::string &value,
357+
mlir::Type target_type
358+
);
359+
360+
/**
361+
* @brief Finds a local variable by name in the current function scope.
362+
*/
363+
std::optional< mlir::Value >
364+
find_local_variable(mlir::Operation *call_op, const std::string &var_name);
365+
366+
/**
367+
* @brief Finds a global symbol (variable or function) by name.
368+
*/
369+
std::optional< mlir::Value > find_global_symbol(
370+
mlir::OpBuilder &builder, mlir::Operation *call_op, const std::string &symbol_name
371+
);
296372
};
297373

298374
} // namespace patchestry::passes

include/patchestry/Passes/PatchSpec.hpp

Lines changed: 44 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ namespace patchestry::passes {
4444
{
4545
ArgumentSourceType source;
4646
std::string name; // Descriptive name for the argument
47+
bool is_reference = false; // Whether the argument is a reference
4748
std::optional< unsigned > index; // Operand/argument index (required for OPERAND type)
4849
std::optional< std::string > symbol; // Symbol name (required for VARIABLE/SYMBOL type)
4950
std::optional< std::string > value; // Constant value (required for CONSTANT type)
@@ -381,6 +382,7 @@ namespace llvm::yaml {
381382
io.mapOptional("index", arg.index);
382383
io.mapOptional("symbol", arg.symbol);
383384
io.mapOptional("value", arg.value);
385+
io.mapOptional("is_reference", arg.is_reference);
384386
}
385387
};
386388

@@ -410,7 +412,7 @@ namespace llvm::yaml {
410412
struct MappingTraits< patchestry::passes::Metadata >
411413
{
412414
static void mapping(IO &io, patchestry::passes::Metadata &metadata) {
413-
io.mapOptional("name", metadata.name);
415+
io.mapRequired("name", metadata.name);
414416
io.mapOptional("description", metadata.description);
415417
io.mapOptional("version", metadata.version);
416418
io.mapOptional("author", metadata.author);
@@ -424,8 +426,8 @@ namespace llvm::yaml {
424426
struct MappingTraits< patchestry::passes::Parameter >
425427
{
426428
static void mapping(IO &io, patchestry::passes::Parameter &param) {
427-
io.mapOptional("name", param.name);
428-
io.mapOptional("type", param.type);
429+
io.mapRequired("name", param.name);
430+
io.mapRequired("type", param.type);
429431
io.mapOptional("description", param.description);
430432
}
431433
};
@@ -436,8 +438,8 @@ namespace llvm::yaml {
436438
{
437439
static void mapping(IO &io, patchestry::passes::Implementation &impl) {
438440
io.mapOptional("language", impl.language);
439-
io.mapOptional("code_file", impl.code_file);
440-
io.mapOptional("function_name", impl.function_name);
441+
io.mapRequired("code_file", impl.code_file);
442+
io.mapRequired("function_name", impl.function_name);
441443
io.mapOptional("parameters", impl.parameters);
442444
io.mapOptional("dependencies", impl.dependencies);
443445
}
@@ -453,7 +455,7 @@ namespace llvm::yaml {
453455
io.mapOptional("description", spec.description);
454456
io.mapOptional("category", spec.category);
455457
io.mapOptional("severity", spec.severity);
456-
io.mapOptional("implementation", spec.implementation);
458+
io.mapRequired("implementation", spec.implementation);
457459
}
458460
};
459461

@@ -473,7 +475,7 @@ namespace llvm::yaml {
473475
struct MappingTraits< patchestry::passes::Action >
474476
{
475477
static void mapping(IO &io, patchestry::passes::Action &action) {
476-
io.mapOptional("patch_id", action.patch_id);
478+
io.mapRequired("patch_id", action.patch_id);
477479
io.mapOptional("description", action.description);
478480
io.mapOptional("arguments", action.arguments);
479481

@@ -496,7 +498,7 @@ namespace llvm::yaml {
496498
struct MappingTraits< patchestry::passes::MatchConfig >
497499
{
498500
static void mapping(IO &io, patchestry::passes::MatchConfig &match) {
499-
io.mapOptional("name", match.name);
501+
io.mapRequired("name", match.name);
500502
io.mapOptional("function_context", match.function_context);
501503
io.mapOptional("argument_matches", match.argument_matches);
502504
io.mapOptional("variable_matches", match.variable_matches);
@@ -520,7 +522,7 @@ namespace llvm::yaml {
520522
struct MappingTraits< patchestry::passes::ContractAction >
521523
{
522524
static void mapping(IO &io, patchestry::passes::ContractAction &contract_action) {
523-
io.mapOptional("id", contract_action.action_id);
525+
io.mapRequired("id", contract_action.action_id);
524526
io.mapOptional("description", contract_action.description);
525527
}
526528
};
@@ -530,10 +532,14 @@ namespace llvm::yaml {
530532
struct MappingTraits< patchestry::passes::PatchAction >
531533
{
532534
static void mapping(IO &io, patchestry::passes::PatchAction &patch_action) {
533-
io.mapOptional("id", patch_action.action_id);
535+
io.mapRequired("id", patch_action.action_id);
534536
io.mapOptional("description", patch_action.description);
535-
io.mapOptional("match", patch_action.match);
536-
io.mapOptional("action", patch_action.action);
537+
io.mapRequired("match", patch_action.match);
538+
io.mapRequired("action", patch_action.action);
539+
if (patch_action.match.empty() || patch_action.action.empty()) {
540+
LOG(ERROR) << "Patch action has no match or action";
541+
return;
542+
}
537543
}
538544
};
539545

@@ -552,9 +558,9 @@ namespace llvm::yaml {
552558
struct MappingTraits< patchestry::passes::PatchLibrary >
553559
{
554560
static void mapping(IO &io, patchestry::passes::PatchLibrary &library) {
555-
io.mapOptional("apiVersion", library.api_version);
556-
io.mapOptional("metadata", library.metadata);
557-
io.mapOptional("patches", library.patches);
561+
io.mapRequired("apiVersion", library.api_version);
562+
io.mapRequired("metadata", library.metadata);
563+
io.mapRequired("patches", library.patches);
558564
}
559565
};
560566

@@ -563,9 +569,9 @@ namespace llvm::yaml {
563569
struct MappingTraits< patchestry::passes::ContractLibrary >
564570
{
565571
static void mapping(IO &io, patchestry::passes::ContractLibrary &library) {
566-
io.mapOptional("apiVersion", library.api_version);
567-
io.mapOptional("metadata", library.metadata);
568-
io.mapOptional("contracts", library.contracts);
572+
io.mapRequired("apiVersion", library.api_version);
573+
io.mapRequired("metadata", library.metadata);
574+
io.mapRequired("contracts", library.contracts);
569575
}
570576
};
571577

@@ -596,6 +602,10 @@ namespace llvm::yaml {
596602
}
597603
libraries.contracts = contracts_config.value();
598604
}
605+
if (libraries.patches.patches.empty() && libraries.contracts.contracts.empty()) {
606+
LOG(ERROR) << "Libraries has no patches or contracts";
607+
return;
608+
}
599609
}
600610
};
601611

@@ -604,7 +614,7 @@ namespace llvm::yaml {
604614
struct MappingTraits< patchestry::passes::MetaPatchConfig >
605615
{
606616
static void mapping(IO &io, patchestry::passes::MetaPatchConfig &meta_patch) {
607-
io.mapOptional("name", meta_patch.name);
617+
io.mapRequired("name", meta_patch.name);
608618
io.mapOptional("id", meta_patch.id);
609619
io.mapOptional("description", meta_patch.description);
610620

@@ -613,7 +623,11 @@ namespace llvm::yaml {
613623
for (const auto &opt : optimization) {
614624
meta_patch.optimization.insert(opt);
615625
}
616-
io.mapOptional("patch_actions", meta_patch.patch_actions);
626+
io.mapRequired("patch_actions", meta_patch.patch_actions);
627+
if (meta_patch.patch_actions.empty()) {
628+
LOG(ERROR) << "Meta patch has no patch actions";
629+
return;
630+
}
617631
}
618632
};
619633

@@ -622,7 +636,7 @@ namespace llvm::yaml {
622636
struct MappingTraits< patchestry::passes::MetaContractConfig >
623637
{
624638
static void mapping(IO &io, patchestry::passes::MetaContractConfig &meta_contract) {
625-
io.mapOptional("name", meta_contract.name);
639+
io.mapRequired("name", meta_contract.name);
626640
io.mapOptional("id", meta_contract.id);
627641
io.mapOptional("description", meta_contract.description);
628642
}
@@ -633,13 +647,18 @@ namespace llvm::yaml {
633647
struct MappingTraits< patchestry::passes::PatchConfiguration >
634648
{
635649
static void mapping(IO &io, patchestry::passes::PatchConfiguration &config) {
636-
io.mapOptional("apiVersion", config.api_version);
637-
io.mapOptional("metadata", config.metadata);
638-
io.mapOptional("target", config.target);
639-
io.mapOptional("libraries", config.libraries);
650+
io.mapRequired("apiVersion", config.api_version);
651+
io.mapRequired("metadata", config.metadata);
652+
io.mapRequired("target", config.target);
653+
io.mapRequired("libraries", config.libraries);
640654
io.mapOptional("execution_order", config.execution_order);
641655
io.mapOptional("meta_patches", config.meta_patches);
642656
io.mapOptional("meta_contracts", config.meta_contracts);
657+
658+
if (config.meta_patches.empty() && config.meta_contracts.empty()) {
659+
LOG(ERROR) << "Patch configuration has no meta patches or meta contracts";
660+
return;
661+
}
643662
}
644663
};
645664

0 commit comments

Comments
 (0)