<commit_before>#    This file is part of Metasm, the Ruby assembly manipulation suite
#    Copyright (C) 2006-2009 <NAME>
#
#    Licence is LGPL, see LICENCE in the top-level directory


require 'metasm/ia32/opcodes'
require 'metasm/ia32/encode'
require 'metasm/parse'

module Metasm
class Ia32
class ModRM
	# may return a SegReg
	# must be called before SegReg parser (which could match only the seg part of a modrm)
	def self.parse(lexer, otok, cpu)
		tok = otok

		# read operand size specifier
		if tok and tok.type == :string and tok.raw =~ /^(?:byte|[dqo]?word|_(\d+)bits)$/
			ptsz =
			if $1
				$1.to_i
			else
				case tok.raw
				when  'byte';   8
				when  'word';  16
				when 'dword';  32
				when 'qword';  64
				when 'oword'; 128
				else raise otok, 'mrm: bad ptr size'
				end
			end
			lexer.skip_space
			if tok = lexer.readtok and tok.type == :string and tok.raw == 'ptr'
				lexer.skip_space
				tok = lexer.readtok
			end
		end

		# read segment selector
		if tok and tok.type == :string and seg = SegReg.s_to_i[tok.raw]
			lexer.skip_space
			seg = SegReg.new(seg)
			if not ntok = lexer.readtok or ntok.type != :punct or ntok.raw != ':'
				raise otok, 'invalid modrm' if ptsz
				lexer.unreadtok ntok
				return seg
			end
			lexer.skip_space
			tok = lexer.readtok
		end

		# ensure we have a modrm
		if not tok or tok.type != :punct or tok.raw != '['
			raise otok, 'invalid modrm' if ptsz or seg
			return
		end
		lexer.skip_space_eol

		# support fasm syntax [fs:eax] for segment selector
		if tok = lexer.readtok and tok.type == :string and not seg and seg = SegReg.s_to_i[tok.raw]
			raise otok, 'invalid modrm' if not ntok = lexer.readtok or ntok.type != :punct or ntok.raw != ':'
			seg = SegReg.new(seg)
			lexer.skip_space_eol
		else
			lexer.unreadtok tok
		end

		# read modrm content as generic expression
		content = Expression.parse(lexer)
		lexer.skip_space_eol
		raise(otok, 'bad modrm') if not content or not ntok = lexer.readtok or ntok.type != :punct or ntok.raw != ']'

		# converts matching externals to Regs in an expression
		regify = lambda { |o|
			case o
			when Expression
				o.lexpr = regify[o.lexpr]
				o.rexpr = regify[o.rexpr]
				o
			when String
				cpu.str_to_reg(o) || o
			else o
			end
		}

		s = i = b = imm = nil

		# assigns the Regs in the expression to base or index field of the modrm
		walker = lambda { |o|
			case o
			when nil
			when Reg
				if b
					raise otok, 'mrm: too many regs' if i
					i = o
					s = 1
				else
					b = o
				end
			when Expression
				if o.op == :* and (o.rexpr.kind_of? Reg or o.lexpr.kind_of? Reg)
					# scaled index
					raise otok, 'mrm: too many indexes' if i
					s = o.lexpr
					i = o.rexpr
					s, i = i, s if s.kind_of? Reg
					raise otok, 'mrm: bad scale' unless s.kind_of? Integer
				elsif o.op == :+
					# recurse
					walker[o.lexpr]
					walker[o.rexpr]
				else
					# found (a part of) the immediate
					imm = Expression[imm, :+, o]
				end
			else
				# found (a part of) the immediate
				imm = Expression[imm, :+, o]
			end
		}<commit_msg>ia32: raise on invalid mrm scale (push [16*eax])<commit_after>#    This file is part of Metasm, the Ruby assembly manipulation suite
#    Copyright (C) 2006-2009 <NAME>
#
#    Licence is LGPL, see LICENCE in the top-level directory


require 'metasm/ia32/opcodes'
require 'metasm/ia32/encode'
require 'metasm/parse'

module Metasm
class Ia32
class ModRM
	# may return a SegReg
	# must be called before SegReg parser (which could match only the seg part of a modrm)
	def self.parse(lexer, otok, cpu)
		tok = otok

		# read operand size specifier
		if tok and tok.type == :string and tok.raw =~ /^(?:byte|[dqo]?word|_(\d+)bits)$/
			ptsz =
			if $1
				$1.to_i
			else
				case tok.raw
				when  'byte';   8
				when  'word';  16
				when 'dword';  32
				when 'qword';  64
				when 'oword'; 128
				else raise otok, 'mrm: bad ptr size'
				end
			end
			lexer.skip_space
			if tok = lexer.readtok and tok.type == :string and tok.raw == 'ptr'
				lexer.skip_space
				tok = lexer.readtok
			end
		end

		# read segment selector
		if tok and tok.type == :string and seg = SegReg.s_to_i[tok.raw]
			lexer.skip_space
			seg = SegReg.new(seg)
			if not ntok = lexer.readtok or ntok.type != :punct or ntok.raw != ':'
				raise otok, 'invalid modrm' if ptsz
				lexer.unreadtok ntok
				return seg
			end
			lexer.skip_space
			tok = lexer.readtok
		end

		# ensure we have a modrm
		if not tok or tok.type != :punct or tok.raw != '['
			raise otok, 'invalid modrm' if ptsz or seg
			return
		end
		lexer.skip_space_eol

		# support fasm syntax [fs:eax] for segment selector
		if tok = lexer.readtok and tok.type == :string and not seg and seg = SegReg.s_to_i[tok.raw]
			raise otok, 'invalid modrm' if not ntok = lexer.readtok or ntok.type != :punct or ntok.raw != ':'
			seg = SegReg.new(seg)
			lexer.skip_space_eol
		else
			lexer.unreadtok tok
		end

		# read modrm content as generic expression
		content = Expression.parse(lexer)
		lexer.skip_space_eol
		raise(otok, 'bad modrm') if not content or not ntok = lexer.readtok or ntok.type != :punct or ntok.raw != ']'

		# converts matching externals to Regs in an expression
		regify = lambda { |o|
			case o
			when Expression
				o.lexpr = regify[o.lexpr]
				o.rexpr = regify[o.rexpr]
				o
			when String
				cpu.str_to_reg(o) || o
			else o
			end
		}

		s = i = b = imm = nil

		# assigns the Regs in the expression to base or index field of the modrm
		walker = lambda { |o|
			case o
			when nil
			when Reg
				if b
					raise otok, 'mrm: too many regs' if i
					i = o
					s = 1
				else
					b = o
				end
			when Expression
				if o.op == :* and (o.rexpr.kind_of? Reg or o.lexpr.kind_of? Reg)
					# scaled index
					raise otok, 'mrm: too many indexes' if i
					s = o.lexpr
					i = o.rexpr
					s, i = i, s if s.kind_of? Reg
					raise otok, "mrm: bad scale #{s}" unless [1, 2, 4, 8].include?(s)
				elsif o.op == :+
					# recurse
					walker[o.lexpr]
					walker[o.rexpr]
				else
					# found (a part of) the immediate
					imm = Expression[imm, :+, o]
				end
			else
				# found (a part of) the immediate
				imm = Expression[imm, :+, o]
			end
		}
{'fraction_non_alphanumeric': 0.10313611380536696, 'fraction_numerical': 0.010022631749110895, 'mean_word_length': 2.4895657078398195, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4852125', 'n_tokens_mistral': 2856, 'n_tokens_neox': 2289, 'n_words': 780}