| ... | ... | @@ -41,9 +41,22 @@ const Action = union(enum) { |
| 41 | 41 | compute_eq: ComputeEqAction, |
| 42 | 42 | }; |
| 43 | 43 | |
| 44 | /// MatchAction is the main building block of standard matchers with optional eat-all token `{*}` |
| 45 | /// and extractors by name such as `{n_value}`. Please note this action is very simplistic in nature |
| 46 | /// i.e., it won't really handle edge cases/nontrivial examples. But given that we do want to use |
| 47 | /// it mainly to test the output of our object format parser-dumpers when testing the linkers, etc. |
| 48 | /// it should be plenty useful in its current form. |
| 44 | 49 | const MatchAction = struct { |
| 45 | 50 | needle: []const u8, |
| 46 | 51 | |
| 52 | /// Will return true if the `needle` was found in the `haystack`. |
| 53 | /// Some examples include: |
| 54 | /// |
| 55 | /// LC 0 => will match in its entirety |
| 56 | /// vmaddr {vmaddr} => will match `vmaddr` and then extract the following value as u64 |
| 57 | /// and save under `vmaddr` global name (see `global_vars` param) |
| 58 | /// name {*}libobjc{*}.dylib => will match `name` followed by a token which contains `libobjc` and `.dylib` |
| 59 | /// in that order with other letters in between |
| 47 | 60 | fn match(act: MatchAction, haystack: []const u8, global_vars: anytype) !bool { |
| 48 | 61 | var hay_it = mem.tokenize(u8, mem.trim(u8, haystack, " "), " "); |
| 49 | 62 | var needle_it = mem.tokenize(u8, mem.trim(u8, act.needle, " "), " "); |
| ... | ... | @@ -81,6 +94,12 @@ const MatchAction = struct { |
| 81 | 94 | } |
| 82 | 95 | }; |
| 83 | 96 | |
| 97 | /// ComputeEqAction can be used to perform an operation on the extracted global variables |
| 98 | /// using the MatchAction. It currently only supports an addition. The operation is required |
| 99 | /// to be specified in Reverse Polish Notation to ease in operator-precedence parsing (well, |
| 100 | /// to avoid any parsing really). |
| 101 | /// For example, if the two extracted values were saved as `vmaddr` and `entryoff` respectively |
| 102 | /// they could then be added with this simple program `vmaddr entryoff +`. |
| 84 | 103 | const ComputeEqAction = struct { |
| 85 | 104 | expected: []const u8, |
| 86 | 105 | var_stack: std.ArrayList([]const u8), |
| ... | ... | @@ -115,23 +134,32 @@ const Check = struct { |
| 115 | 134 | } |
| 116 | 135 | }; |
| 117 | 136 | |
| 137 | /// Creates a new sequence of actions with `phrase` as the first anchor searched phrase. |
| 118 | 138 | pub fn check(self: *CheckObjectStep, phrase: []const u8) void { |
| 119 | 139 | var new_check = Check.create(self.builder); |
| 120 | 140 | new_check.match(phrase); |
| 121 | 141 | self.checks.append(new_check) catch unreachable; |
| 122 | 142 | } |
| 123 | 143 | |
| 144 | /// Adds another searched phrase to the latest created Check with `CheckObjectStep.check(...)`. |
| 145 | /// Asserts at least one check already exists. |
| 124 | 146 | pub fn checkNext(self: *CheckObjectStep, phrase: []const u8) void { |
| 125 | 147 | assert(self.checks.items.len > 0); |
| 126 | 148 | const last = &self.checks.items[self.checks.items.len - 1]; |
| 127 | 149 | last.match(phrase); |
| 128 | 150 | } |
| 129 | 151 | |
| 152 | /// Creates a new check checking specifically symbol table parsed and dumped from the object |
| 153 | /// file. |
| 154 | /// Issuing this check will force parsing and dumping of the symbol table. |
| 130 | 155 | pub fn checkInSymtab(self: *CheckObjectStep) void { |
| 131 | 156 | self.dump_symtab = true; |
| 132 | 157 | self.check("symtab"); |
| 133 | 158 | } |
| 134 | 159 | |
| 160 | /// Creates a new standalone, singular check which allows running simple binary operations |
| 161 | /// on the extracted variables. It will then compare the reduced program with the value of |
| 162 | /// the expected variable. |
| 135 | 163 | pub fn checkComputeEq(self: *CheckObjectStep, program: []const u8, expected: []const u8) void { |
| 136 | 164 | const gpa = self.builder.allocator; |
| 137 | 165 | var ca = ComputeEqAction{ |