seccomp-tools 1.6.2 → 1.7.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +167 -0
- data/README.md +280 -42
- data/completions/_seccomp-tools +83 -0
- data/completions/seccomp-tools.bash +59 -0
- data/completions/seccomp-tools.fish +52 -0
- data/ext/ptrace/ptrace.c +2 -2
- data/lib/seccomp-tools/asm/asm.rb +9 -4
- data/lib/seccomp-tools/asm/compiler.rb +32 -2
- data/lib/seccomp-tools/asm/sasm.tab.rb +27 -19
- data/lib/seccomp-tools/asm/sasm.y +15 -7
- data/lib/seccomp-tools/asm/scalar.rb +50 -7
- data/lib/seccomp-tools/asm/scanner.rb +33 -1
- data/lib/seccomp-tools/asm/statement.rb +14 -5
- data/lib/seccomp-tools/asm/token.rb +19 -1
- data/lib/seccomp-tools/audit/catalog.rb +69 -0
- data/lib/seccomp-tools/audit/checks/arch_unchecked.rb +41 -0
- data/lib/seccomp-tools/audit/checks/dangerous_allow.rb +34 -0
- data/lib/seccomp-tools/audit/checks/orw_chain.rb +41 -0
- data/lib/seccomp-tools/audit/checks/permissive_default.rb +29 -0
- data/lib/seccomp-tools/audit/checks/syscall_alt_gap.rb +44 -0
- data/lib/seccomp-tools/audit/checks/x32_guard.rb +46 -0
- data/lib/seccomp-tools/audit/checks.rb +42 -0
- data/lib/seccomp-tools/audit/finding.rb +25 -0
- data/lib/seccomp-tools/audit/policy.rb +126 -0
- data/lib/seccomp-tools/audit/report.rb +98 -0
- data/lib/seccomp-tools/audit.rb +48 -0
- data/lib/seccomp-tools/bpf.rb +27 -17
- data/lib/seccomp-tools/cli/asm.rb +6 -2
- data/lib/seccomp-tools/cli/audit.rb +86 -0
- data/lib/seccomp-tools/cli/base.rb +51 -8
- data/lib/seccomp-tools/cli/cli.rb +9 -3
- data/lib/seccomp-tools/cli/completion.rb +40 -0
- data/lib/seccomp-tools/cli/disasm.rb +9 -5
- data/lib/seccomp-tools/cli/dump.rb +37 -52
- data/lib/seccomp-tools/cli/dumpable.rb +79 -0
- data/lib/seccomp-tools/cli/emu.rb +20 -5
- data/lib/seccomp-tools/cli/explain.rb +51 -0
- data/lib/seccomp-tools/cli/filter_input.rb +130 -0
- data/lib/seccomp-tools/const.rb +98 -15
- data/lib/seccomp-tools/consts/sys_arg.rb +43 -5
- data/lib/seccomp-tools/consts/sys_nr/aarch64.rb +52 -1
- data/lib/seccomp-tools/consts/sys_nr/amd64.rb +53 -1
- data/lib/seccomp-tools/consts/sys_nr/i386.rb +83 -2
- data/lib/seccomp-tools/consts/sys_nr/riscv64.rb +332 -0
- data/lib/seccomp-tools/consts/sys_nr/s390x.rb +30 -1
- data/lib/seccomp-tools/disasm/disasm.rb +30 -12
- data/lib/seccomp-tools/dumper.rb +67 -36
- data/lib/seccomp-tools/emulator.rb +40 -15
- data/lib/seccomp-tools/error.rb +4 -2
- data/lib/seccomp-tools/explain/analysis.rb +67 -0
- data/lib/seccomp-tools/explain/path_facts.rb +110 -0
- data/lib/seccomp-tools/explain/qword.rb +204 -0
- data/lib/seccomp-tools/explain/renderer.rb +128 -0
- data/lib/seccomp-tools/explain/summary.rb +218 -0
- data/lib/seccomp-tools/explain/verdict.rb +44 -0
- data/lib/seccomp-tools/explain.rb +38 -0
- data/lib/seccomp-tools/instruction/alu.rb +14 -9
- data/lib/seccomp-tools/instruction/base.rb +39 -10
- data/lib/seccomp-tools/instruction/jmp.rb +50 -23
- data/lib/seccomp-tools/instruction/ld.rb +46 -21
- data/lib/seccomp-tools/instruction/ldx.rb +4 -3
- data/lib/seccomp-tools/instruction/misc.rb +11 -9
- data/lib/seccomp-tools/instruction/ret.rb +12 -6
- data/lib/seccomp-tools/instruction/st.rb +15 -6
- data/lib/seccomp-tools/instruction/stx.rb +4 -3
- data/lib/seccomp-tools/logger.rb +14 -1
- data/lib/seccomp-tools/symbolic/constraint.rb +80 -0
- data/lib/seccomp-tools/symbolic/executor.rb +210 -0
- data/lib/seccomp-tools/symbolic/expr.rb +185 -0
- data/lib/seccomp-tools/symbolic/state.rb +82 -0
- data/lib/seccomp-tools/syscall.rb +73 -23
- data/lib/seccomp-tools/util.rb +76 -11
- data/lib/seccomp-tools/version.rb +1 -1
- data/lib/seccomp-tools.rb +10 -1
- metadata +36 -24
- data/lib/seccomp-tools/disasm/context.rb +0 -171
data/lib/seccomp-tools/util.rb
CHANGED
|
@@ -1,38 +1,80 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module SeccompTools
|
|
4
|
-
#
|
|
4
|
+
# Utility methods shared across the library: architecture detection and terminal colorizing.
|
|
5
5
|
module Util
|
|
6
6
|
module_function
|
|
7
7
|
|
|
8
8
|
# Get currently supported architectures.
|
|
9
|
+
#
|
|
10
|
+
# Derived from the syscall tables shipped under +consts/sys_nr/+.
|
|
9
11
|
# @return [Array<Symbol>]
|
|
10
|
-
#
|
|
12
|
+
# Architecture names, sorted.
|
|
11
13
|
def supported_archs
|
|
12
14
|
@supported_archs ||= Dir.glob(File.join(__dir__, 'consts', 'sys_nr', '*.rb'))
|
|
13
15
|
.map { |f| File.basename(f, '.rb').to_sym }
|
|
14
16
|
.sort
|
|
15
17
|
end
|
|
16
18
|
|
|
19
|
+
# Whether the host operating system is Linux, where the +ptrace+-based dumping works.
|
|
20
|
+
# @return [Boolean]
|
|
21
|
+
def linux?
|
|
22
|
+
RbConfig::CONFIG['host_os'].include?('linux')
|
|
23
|
+
end
|
|
24
|
+
|
|
17
25
|
# Detect system architecture.
|
|
18
26
|
# @return [Symbol]
|
|
27
|
+
# One of {supported_archs}, or +:unknown+ if the host CPU is not supported.
|
|
19
28
|
def system_arch
|
|
20
29
|
case RbConfig::CONFIG['host_cpu']
|
|
21
30
|
when /x86_64/ then :amd64
|
|
22
31
|
when /i386/ then :i386
|
|
23
32
|
when /aarch64/ then :aarch64
|
|
33
|
+
when /riscv64/ then :riscv64
|
|
24
34
|
when /s390x/ then :s390x
|
|
25
35
|
else :unknown
|
|
26
36
|
end
|
|
27
37
|
end
|
|
28
38
|
|
|
39
|
+
# ELF +e_machine+ values (the halfword at offset 18) of the architectures seccomp-tools supports,
|
|
40
|
+
# as they are laid out in the file - so the big-endian s390x reads the other way around. The keys
|
|
41
|
+
# are binary strings (+.b+) to match what is read off the file: this source is UTF-8, where a
|
|
42
|
+
# literal such as +"\xb7\x00"+ would never compare equal to those bytes.
|
|
43
|
+
ELF_MACHINE = {
|
|
44
|
+
"\x03\x00".b => :i386,
|
|
45
|
+
"\x3e\x00".b => :amd64,
|
|
46
|
+
"\xb7\x00".b => :aarch64,
|
|
47
|
+
"\xf3\x00".b => :riscv64,
|
|
48
|
+
"\x00\x16".b => :s390x
|
|
49
|
+
}.freeze
|
|
50
|
+
|
|
51
|
+
# The architecture a running process was built for, read from the ELF header of its executable.
|
|
52
|
+
#
|
|
53
|
+
# Filters dumped from another process are numbered for *its* architecture, so this is what makes
|
|
54
|
+
# the syscall names right when it differs from the host.
|
|
55
|
+
# @param [Integer] pid
|
|
56
|
+
# Process identifier.
|
|
57
|
+
# @return [Symbol?]
|
|
58
|
+
# One of {supported_archs}, or +nil+ when the executable cannot be read (no +/proc+, the
|
|
59
|
+
# process is gone, permission denied) or its machine type is not one we know.
|
|
60
|
+
def process_arch(pid)
|
|
61
|
+
File.open("/proc/#{pid}/exe", 'rb') do |f|
|
|
62
|
+
f.pos = 18
|
|
63
|
+
ELF_MACHINE[f.read(2)]
|
|
64
|
+
end
|
|
65
|
+
rescue SystemCallError
|
|
66
|
+
nil
|
|
67
|
+
end
|
|
68
|
+
|
|
29
69
|
# Enable colorize.
|
|
70
|
+
#
|
|
71
|
+
# Colors are still only emitted when the output is a tty, see {colorize_enabled?}.
|
|
30
72
|
# @return [void]
|
|
31
73
|
def enable_color!
|
|
32
74
|
@disable_color = false
|
|
33
75
|
end
|
|
34
76
|
|
|
35
|
-
# Disable colorize.
|
|
77
|
+
# Disable colorize, {colorize} becomes a no-op regardless of the output being a tty.
|
|
36
78
|
# @return [void]
|
|
37
79
|
def disable_color!
|
|
38
80
|
@disable_color = true
|
|
@@ -40,28 +82,35 @@ module SeccompTools
|
|
|
40
82
|
|
|
41
83
|
# Is colorize enabled?
|
|
42
84
|
# @return [Boolean]
|
|
85
|
+
# +true+ only if colors have not been disabled by {disable_color!} and +$stdout+ is a tty.
|
|
43
86
|
def colorize_enabled?
|
|
44
87
|
!@disable_color && $stdout.tty?
|
|
45
88
|
end
|
|
46
89
|
|
|
47
90
|
# color code of light yellow
|
|
48
91
|
LIGHT_YELLOW = "\e[38;5;230m"
|
|
49
|
-
# Color codes for pretty print.
|
|
92
|
+
# Color codes for pretty print. +error+, +warn+ and +info+ are severities rather than parts of a
|
|
93
|
+
# filter, shading from alarming to quiet; {SeccompTools::Logger} colors its own levels by the
|
|
94
|
+
# same names.
|
|
50
95
|
COLOR_CODE = {
|
|
51
96
|
esc_m: "\e[0m",
|
|
52
97
|
syscall: "\e[38;5;120m", # light green
|
|
53
98
|
arch: LIGHT_YELLOW,
|
|
54
99
|
args: LIGHT_YELLOW,
|
|
55
100
|
gray: "\e[2m",
|
|
56
|
-
error: "\e[38;5;196m" # heavy red
|
|
101
|
+
error: "\e[38;5;196m", # heavy red
|
|
102
|
+
warn: LIGHT_YELLOW,
|
|
103
|
+
info: "\e[38;5;110m" # light blue
|
|
57
104
|
}.freeze
|
|
58
|
-
#
|
|
59
|
-
#
|
|
60
|
-
#
|
|
105
|
+
# Wrap contents with terminal color codes.
|
|
106
|
+
#
|
|
107
|
+
# Returns +s+ unchanged when {colorize_enabled?} is +false+.
|
|
108
|
+
# @param [#to_s] s
|
|
109
|
+
# Contents to be wrapped.
|
|
61
110
|
# @param [Symbol?] t
|
|
62
|
-
#
|
|
111
|
+
# Which kind of color to use, valid symbols are the keys of {Util::COLOR_CODE}.
|
|
63
112
|
# @return [String]
|
|
64
|
-
#
|
|
113
|
+
# +s+ wrapped with color codes.
|
|
65
114
|
def colorize(s, t: nil)
|
|
66
115
|
s = s.to_s
|
|
67
116
|
return s unless colorize_enabled?
|
|
@@ -71,13 +120,29 @@ module SeccompTools
|
|
|
71
120
|
"#{color}#{s.sub(cc[:esc_m], cc[:esc_m] + color)}#{cc[:esc_m]}"
|
|
72
121
|
end
|
|
73
122
|
|
|
123
|
+
# Does the file at +path+ start with the ELF magic bytes?
|
|
124
|
+
#
|
|
125
|
+
# Used to tell an executable apart from a raw BPF blob.
|
|
126
|
+
# @param [String] path
|
|
127
|
+
# Path to the file to check.
|
|
128
|
+
# @return [Boolean]
|
|
129
|
+
# +false+ when the file cannot be read.
|
|
130
|
+
def elf?(path)
|
|
131
|
+
File.binread(path, 4) == "\x7fELF".b
|
|
132
|
+
rescue SystemCallError
|
|
133
|
+
false
|
|
134
|
+
end
|
|
135
|
+
|
|
74
136
|
# Get content of filename under directory templates/.
|
|
75
137
|
#
|
|
76
138
|
# @param [String] filename
|
|
77
|
-
#
|
|
139
|
+
# Basename of a file under +lib/seccomp-tools/templates/+.
|
|
78
140
|
#
|
|
79
141
|
# @return [String]
|
|
80
142
|
# Content of the file.
|
|
143
|
+
#
|
|
144
|
+
# @raise [Errno::ENOENT]
|
|
145
|
+
# If no such template exists.
|
|
81
146
|
def template(filename)
|
|
82
147
|
File.binread(File.join(__dir__, 'templates', filename))
|
|
83
148
|
end
|
data/lib/seccomp-tools.rb
CHANGED
|
@@ -2,7 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
# @author david942j
|
|
4
4
|
|
|
5
|
-
#
|
|
5
|
+
# Toolkit for working with seccomp BPF filters.
|
|
6
|
+
#
|
|
7
|
+
# The library entry points are {Asm.asm} to compile assembly into raw BPF, {Disasm.disasm} to turn
|
|
8
|
+
# raw BPF back into readable assembly, {Dumper.dump} to capture the filters a process installs, and
|
|
9
|
+
# {Emulator} to run a filter against a hypothetical syscall.
|
|
10
|
+
#
|
|
11
|
+
# @example
|
|
12
|
+
# raw = SeccompTools::Asm.asm("return ALLOW\n", arch: :amd64)
|
|
13
|
+
# SeccompTools::Disasm.disasm(raw, arch: :amd64, display_bpf: false)
|
|
14
|
+
# #=> "0000: return ALLOW\n"
|
|
6
15
|
module SeccompTools
|
|
7
16
|
end
|
|
8
17
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: seccomp-tools
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.7.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- david942j
|
|
@@ -85,14 +85,14 @@ dependencies:
|
|
|
85
85
|
requirements:
|
|
86
86
|
- - "~>"
|
|
87
87
|
- !ruby/object:Gem::Version
|
|
88
|
-
version: '0
|
|
88
|
+
version: '1.0'
|
|
89
89
|
type: :development
|
|
90
90
|
prerelease: false
|
|
91
91
|
version_requirements: !ruby/object:Gem::Requirement
|
|
92
92
|
requirements:
|
|
93
93
|
- - "~>"
|
|
94
94
|
- !ruby/object:Gem::Version
|
|
95
|
-
version: '0
|
|
95
|
+
version: '1.0'
|
|
96
96
|
- !ruby/object:Gem::Dependency
|
|
97
97
|
name: yard
|
|
98
98
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -121,26 +121,6 @@ dependencies:
|
|
|
121
121
|
- - ">="
|
|
122
122
|
- !ruby/object:Gem::Version
|
|
123
123
|
version: '0'
|
|
124
|
-
- !ruby/object:Gem::Dependency
|
|
125
|
-
name: os
|
|
126
|
-
requirement: !ruby/object:Gem::Requirement
|
|
127
|
-
requirements:
|
|
128
|
-
- - "~>"
|
|
129
|
-
- !ruby/object:Gem::Version
|
|
130
|
-
version: '1.1'
|
|
131
|
-
- - ">="
|
|
132
|
-
- !ruby/object:Gem::Version
|
|
133
|
-
version: 1.1.1
|
|
134
|
-
type: :runtime
|
|
135
|
-
prerelease: false
|
|
136
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
137
|
-
requirements:
|
|
138
|
-
- - "~>"
|
|
139
|
-
- !ruby/object:Gem::Version
|
|
140
|
-
version: '1.1'
|
|
141
|
-
- - ">="
|
|
142
|
-
- !ruby/object:Gem::Version
|
|
143
|
-
version: 1.1.1
|
|
144
124
|
- !ruby/object:Gem::Dependency
|
|
145
125
|
name: racc
|
|
146
126
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -166,9 +146,13 @@ extensions:
|
|
|
166
146
|
- ext/ptrace/extconf.rb
|
|
167
147
|
extra_rdoc_files: []
|
|
168
148
|
files:
|
|
149
|
+
- CHANGELOG.md
|
|
169
150
|
- LICENSE
|
|
170
151
|
- README.md
|
|
171
152
|
- bin/seccomp-tools
|
|
153
|
+
- completions/_seccomp-tools
|
|
154
|
+
- completions/seccomp-tools.bash
|
|
155
|
+
- completions/seccomp-tools.fish
|
|
172
156
|
- ext/ptrace/extconf.rb
|
|
173
157
|
- ext/ptrace/ptrace.c
|
|
174
158
|
- lib/seccomp-tools.rb
|
|
@@ -180,24 +164,48 @@ files:
|
|
|
180
164
|
- lib/seccomp-tools/asm/scanner.rb
|
|
181
165
|
- lib/seccomp-tools/asm/statement.rb
|
|
182
166
|
- lib/seccomp-tools/asm/token.rb
|
|
167
|
+
- lib/seccomp-tools/audit.rb
|
|
168
|
+
- lib/seccomp-tools/audit/catalog.rb
|
|
169
|
+
- lib/seccomp-tools/audit/checks.rb
|
|
170
|
+
- lib/seccomp-tools/audit/checks/arch_unchecked.rb
|
|
171
|
+
- lib/seccomp-tools/audit/checks/dangerous_allow.rb
|
|
172
|
+
- lib/seccomp-tools/audit/checks/orw_chain.rb
|
|
173
|
+
- lib/seccomp-tools/audit/checks/permissive_default.rb
|
|
174
|
+
- lib/seccomp-tools/audit/checks/syscall_alt_gap.rb
|
|
175
|
+
- lib/seccomp-tools/audit/checks/x32_guard.rb
|
|
176
|
+
- lib/seccomp-tools/audit/finding.rb
|
|
177
|
+
- lib/seccomp-tools/audit/policy.rb
|
|
178
|
+
- lib/seccomp-tools/audit/report.rb
|
|
183
179
|
- lib/seccomp-tools/bpf.rb
|
|
184
180
|
- lib/seccomp-tools/cli/asm.rb
|
|
181
|
+
- lib/seccomp-tools/cli/audit.rb
|
|
185
182
|
- lib/seccomp-tools/cli/base.rb
|
|
186
183
|
- lib/seccomp-tools/cli/cli.rb
|
|
184
|
+
- lib/seccomp-tools/cli/completion.rb
|
|
187
185
|
- lib/seccomp-tools/cli/disasm.rb
|
|
188
186
|
- lib/seccomp-tools/cli/dump.rb
|
|
187
|
+
- lib/seccomp-tools/cli/dumpable.rb
|
|
189
188
|
- lib/seccomp-tools/cli/emu.rb
|
|
189
|
+
- lib/seccomp-tools/cli/explain.rb
|
|
190
|
+
- lib/seccomp-tools/cli/filter_input.rb
|
|
190
191
|
- lib/seccomp-tools/const.rb
|
|
191
192
|
- lib/seccomp-tools/consts/sys_arg.rb
|
|
192
193
|
- lib/seccomp-tools/consts/sys_nr/aarch64.rb
|
|
193
194
|
- lib/seccomp-tools/consts/sys_nr/amd64.rb
|
|
194
195
|
- lib/seccomp-tools/consts/sys_nr/i386.rb
|
|
196
|
+
- lib/seccomp-tools/consts/sys_nr/riscv64.rb
|
|
195
197
|
- lib/seccomp-tools/consts/sys_nr/s390x.rb
|
|
196
|
-
- lib/seccomp-tools/disasm/context.rb
|
|
197
198
|
- lib/seccomp-tools/disasm/disasm.rb
|
|
198
199
|
- lib/seccomp-tools/dumper.rb
|
|
199
200
|
- lib/seccomp-tools/emulator.rb
|
|
200
201
|
- lib/seccomp-tools/error.rb
|
|
202
|
+
- lib/seccomp-tools/explain.rb
|
|
203
|
+
- lib/seccomp-tools/explain/analysis.rb
|
|
204
|
+
- lib/seccomp-tools/explain/path_facts.rb
|
|
205
|
+
- lib/seccomp-tools/explain/qword.rb
|
|
206
|
+
- lib/seccomp-tools/explain/renderer.rb
|
|
207
|
+
- lib/seccomp-tools/explain/summary.rb
|
|
208
|
+
- lib/seccomp-tools/explain/verdict.rb
|
|
201
209
|
- lib/seccomp-tools/instruction/alu.rb
|
|
202
210
|
- lib/seccomp-tools/instruction/base.rb
|
|
203
211
|
- lib/seccomp-tools/instruction/instruction.rb
|
|
@@ -209,6 +217,10 @@ files:
|
|
|
209
217
|
- lib/seccomp-tools/instruction/st.rb
|
|
210
218
|
- lib/seccomp-tools/instruction/stx.rb
|
|
211
219
|
- lib/seccomp-tools/logger.rb
|
|
220
|
+
- lib/seccomp-tools/symbolic/constraint.rb
|
|
221
|
+
- lib/seccomp-tools/symbolic/executor.rb
|
|
222
|
+
- lib/seccomp-tools/symbolic/expr.rb
|
|
223
|
+
- lib/seccomp-tools/symbolic/state.rb
|
|
212
224
|
- lib/seccomp-tools/syscall.rb
|
|
213
225
|
- lib/seccomp-tools/templates/asm.amd64.asm
|
|
214
226
|
- lib/seccomp-tools/templates/asm.c
|
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module SeccompTools
|
|
4
|
-
module Disasm
|
|
5
|
-
# @private
|
|
6
|
-
#
|
|
7
|
-
# Context for disassembler to analyze.
|
|
8
|
-
#
|
|
9
|
-
# This class maintains:
|
|
10
|
-
# * if +reg/mem+ can be one of +data[*]+
|
|
11
|
-
# * if +data[0]+ (i.e. sys_number) is a known value
|
|
12
|
-
class Context
|
|
13
|
-
# @private
|
|
14
|
-
#
|
|
15
|
-
# Records the type and value.
|
|
16
|
-
class Value
|
|
17
|
-
attr_reader :val # @return [Integer]
|
|
18
|
-
|
|
19
|
-
# @param [:imm, :data, :mem] rel
|
|
20
|
-
# @param [Integer?] val
|
|
21
|
-
def initialize(rel: :imm, val: nil)
|
|
22
|
-
@rel = rel
|
|
23
|
-
@val = val
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
# @return [Boolean]
|
|
27
|
-
def data?
|
|
28
|
-
@rel == :data
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
# @return [Boolean]
|
|
32
|
-
def imm?
|
|
33
|
-
@rel == :imm && @val.is_a?(Integer)
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
# Defines hash function.
|
|
37
|
-
# @return [Integer]
|
|
38
|
-
def hash
|
|
39
|
-
[@rel, @val].hash
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
# Defines +eql?+.
|
|
43
|
-
#
|
|
44
|
-
# @param [Context::Value] other
|
|
45
|
-
# @return [Boolean]
|
|
46
|
-
def eql?(other)
|
|
47
|
-
@val == other.val && @rel == other.instance_variable_get(:@rel)
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
# @return [{Integer, Symbol => Context::Value}] Records reg and mem values.
|
|
52
|
-
attr_reader :values
|
|
53
|
-
# @return [Array<Integer?>] Records the known value of data.
|
|
54
|
-
attr_reader :known_data
|
|
55
|
-
|
|
56
|
-
# Instantiate a {Context} object.
|
|
57
|
-
# @param [{Integer, Symbol => Context::Value?}] values
|
|
58
|
-
# Value to be set to +reg/mem+.
|
|
59
|
-
# @param [Array<Integer?>] known_data
|
|
60
|
-
# Records which index of data is known.
|
|
61
|
-
# It's used for tracking when the syscall number is known, which can be used to display argument names of the
|
|
62
|
-
# syscall.
|
|
63
|
-
def initialize(values: {}, known_data: [])
|
|
64
|
-
@values = values
|
|
65
|
-
16.times { |i| @values[i] ||= Value.new(rel: :mem, val: i) } # make @values always has all keys
|
|
66
|
-
@values[:a] ||= Value.new
|
|
67
|
-
@values[:x] ||= Value.new
|
|
68
|
-
@known_data = known_data
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
# Is used for the ld/ldx instructions.
|
|
72
|
-
#
|
|
73
|
-
# @param [#downcase, :a, :x] reg
|
|
74
|
-
# Register to be set
|
|
75
|
-
# @return [void]
|
|
76
|
-
def load(reg, rel: nil, val: nil)
|
|
77
|
-
reg = reg.downcase.to_sym
|
|
78
|
-
values[reg] = if rel == :mem
|
|
79
|
-
values[val]
|
|
80
|
-
else
|
|
81
|
-
Value.new(rel:, val:)
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
# Is used for the st/stx instructions.
|
|
86
|
-
#
|
|
87
|
-
# @param [Integer] idx
|
|
88
|
-
# Index of +mem+ array.
|
|
89
|
-
# @param [#downcase, :a, :x] reg
|
|
90
|
-
# Register.
|
|
91
|
-
#
|
|
92
|
-
# @return [void]
|
|
93
|
-
def store(idx, reg)
|
|
94
|
-
raise RangeError, "Expect 0 <= idx < 16, got #{idx}." unless idx.between?(0, 15)
|
|
95
|
-
|
|
96
|
-
values[idx] = values[reg.downcase.to_sym]
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
# Hints context that current value of register A equals to +val+.
|
|
100
|
-
#
|
|
101
|
-
# @param [Integer, :x] val
|
|
102
|
-
# An immediate value or the symbol x.
|
|
103
|
-
# @return [self]
|
|
104
|
-
# Returns the object itself.
|
|
105
|
-
def eql!(val)
|
|
106
|
-
tap do
|
|
107
|
-
# only cares when A is fetched from data
|
|
108
|
-
next unless a.data?
|
|
109
|
-
next known_data[a.val] = val if val.is_a?(Integer)
|
|
110
|
-
# A == X, we can handle these cases:
|
|
111
|
-
# * X is an immi
|
|
112
|
-
# * X is a known data
|
|
113
|
-
next unless x.data? || x.imm?
|
|
114
|
-
next known_data[a.val] = x.val if x.imm?
|
|
115
|
-
|
|
116
|
-
known_data[a.val] = known_data[x.val]
|
|
117
|
-
end
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
# Implements a deep dup.
|
|
121
|
-
# @return [Context]
|
|
122
|
-
def dup
|
|
123
|
-
Context.new(values: values.dup, known_data: known_data.dup)
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
# Register A.
|
|
127
|
-
# @return [Context::Value]
|
|
128
|
-
def a
|
|
129
|
-
values[:a]
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
# Register X.
|
|
133
|
-
# @return [Context::Value]
|
|
134
|
-
def x
|
|
135
|
-
values[:x]
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
# For conveniently get instance variable.
|
|
139
|
-
# @param [String, Symbol, Integer] key
|
|
140
|
-
# @return [Context::Value]
|
|
141
|
-
def [](key)
|
|
142
|
-
return values[key] if key.is_a?(Integer) # mem
|
|
143
|
-
|
|
144
|
-
values[key.downcase.to_sym]
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
# For conveniently set an instance variable.
|
|
148
|
-
# @param [#downcase, :a, :x] reg
|
|
149
|
-
# Can be +'A', 'a', :a, 'X', 'x', :x+.
|
|
150
|
-
# @param [Value] val
|
|
151
|
-
# Value to set.
|
|
152
|
-
# @return [void]
|
|
153
|
-
def []=(reg, val)
|
|
154
|
-
values[reg.downcase.to_sym] = val
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
# For +Set+ to compare two {Context} objects.
|
|
158
|
-
# @param [Context] other
|
|
159
|
-
# @return [Boolean]
|
|
160
|
-
def eql?(other)
|
|
161
|
-
values.eql?(other.values) && known_data.eql?(other.known_data)
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
# For +Set+ to get the hash value.
|
|
165
|
-
# @return [Integer]
|
|
166
|
-
def hash
|
|
167
|
-
[values, known_data].hash
|
|
168
|
-
end
|
|
169
|
-
end
|
|
170
|
-
end
|
|
171
|
-
end
|