<commit_before>// ----------------------------------------------------------------------------
// PSP Player Emulation Suite
// Copyright (C) 2006 <NAME> (noxa)
// Licensed under the LGPL - see License.txt in the project root for details
// ----------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;

namespace Noxa.Emulation.Psp.Player.Debugger.Model
{
	class MethodBody
	{
		public string Name;
		public uint TotalLines;

		public readonly uint Address;
		public readonly uint Length;

		public Instruction[] Instructions;

		public int LocalsSize;
		public Label[] Labels;

		public CodeReference[] CodeReferences;
		public MemoryReference[] MemoryReferences;
		public List<ExternalReference> IncomingReferences;
		public List<ExternalReference> OutgoingReferences;

		public MethodBody( uint address, uint length, Instruction[] instructions )
		{
			this.Name = string.Format( "sub_{0:X8}", address );
			this.TotalLines = length / 4;

			this.Address = address;
			this.Length = length;

			this.IncomingReferences = new List<ExternalReference>();
			this.OutgoingReferences = new List<ExternalReference>();

			if( instructions != null )
				this.Populate( instructions );
		}

		public void Populate( Instruction[] instructions )
		{
			this.Instructions = instructions;

			// - determine locals (loop for first addiu $sp, $sp, [size]
			// - find all labels (branch targets)

			bool foundSpMod = false;
			List<Label> labels = new List<Label>();
			List<CodeReference> codeRefs = new List<CodeReference>();
			List<MemoryReference> memRefs = new List<MemoryReference>();
			foreach( Instruction instruction in instructions )
			{
				if( instruction.IsBranch == true )
				{
					uint target = 0;
					foreach( Operand op in instruction.Operands )
					{
						if( op.Type == OperandType.BranchTarget )
						{
							target = ( uint )( ( int )instruction.Address + 4 + op.Immediate );
							break;
						}
					}
					if( target > 0 )
						this.AddLabelReference( labels, instruction, target );
				}
				else if( instruction.IsJump == true )
				{
					uint target = 0;
					foreach( Operand op in instruction.Operands )
					{
						if( op.Type == OperandType.JumpTarget )
						{
							target = ( uint )op.Immediate;
							break;
						}
					}
					if( ( target >= this.Address ) && ( target < ( this.Address + this.Length ) ) )
						this.AddLabelReference( labels, instruction, target );
					else
						this.AddCodeReference( codeRefs, instruction, target );
				}
				else if( instruction.IsLoad == true )
				{
				}
				else if( instruction.IsStore == true )
				{
				}
				if( ( foundSpMod == false ) && ( instruction.Opcode.InstructionEntry.Name == "addiu" ) )
				{
					foundSpMod = true;
					int adjustment = instruction.Operands[ 2 ].Immediate / 4;
					this.LocalsSize = -adjustment;
				}
			}

			// Sort all
			labels.Sort( delegate( Label a, Label b )
			{
				return a.Address.CompareTo( b.Address );
			} );
			this.Labels = labels.ToArray();
			codeRefs.Sort( delegate( CodeReference a, CodeReference b )
			{
				return a.Address.CompareTo( b.Address );
			} );
			this.CodeReferences = codeRefs.ToArray();
			memRefs.Sort( delegate( MemoryReference a, MemoryReference b )
			{
				return a.Address.CompareTo( b.Address );
			} );
			this.MemoryReferences = memRefs.ToArray();
		}

		private void AddLabelReference( List<Label> labels, Instruction instruction, uint target )
		{
			foreach( Label label in labels )
			{
				if( label.Address == target )
				{
					label.References.Add( instruction );
					return;
				}
			}
			Label newLabel = new Label();
			newLabel.Name = string.Format( "loc_{0:X8}", target );
			newLabel.Address = target;
			newLabel.References.Add( instruction );
			labels.Add( newLabel );
		}

		private void AddCodeReference( List<CodeReference> codeRefs, Instruction instruction, uint target )
		{
			foreach( CodeReference codeRef in codeRefs )
			{
				if( codeRef.Address == target )
				{
					codeRef.References.Add( instruction );
					instruction.Reference = codeRef;
					return;
				}
			}
			CodeReference newCodeRef = new CodeReference();
			newCodeRef.Address = target;
			newCodeRef.References.Add( instruction );
			newCodeRef.Instruction = instruction;
			instruction.Reference = newCodeRef;
			codeRefs.Add( newCodeRef );
		}

		private void AddMemoryReference( List<MemoryReference> memRefs, Instruction instruction, uint target, bool isRead )
		{
			foreach( MemoryReference memRef in memRefs )
			{
				if( memRef.Address == target )
				{
					memRef.References.Add( instruction );
					if( isRead == true )
						memRef.Reads++;
					else
						memRef.Writes++;
					instruction.Reference = memRef;
					return;
				}
			}
			MemoryReference newMemRef = new MemoryReference();
			newMemRef.Address = target;
			newMemRef.References.Add( instruction );
			if( isRead == true )
				newMemRef.Reads++;
			else
				newMemRef.Writes++;
			newMemRef.Instruction = instruction;
			instruction.Reference = newMemRef;<commit_msg>Added basic memory reference detection - doesn't handle branches/etc (but IDA doesn't seem to either). For now it's fine.<commit_after>// ----------------------------------------------------------------------------
// PSP Player Emulation Suite
// Copyright (C) 2006 <NAME> (noxa)
// Licensed under the LGPL - see License.txt in the project root for details
// ----------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;

namespace Noxa.Emulation.Psp.Player.Debugger.Model
{
	class MethodBody
	{
		public string Name;
		public uint TotalLines;

		public readonly uint Address;
		public readonly uint Length;

		public Instruction[] Instructions;

		public int LocalsSize;
		public Label[] Labels;

		public CodeReference[] CodeReferences;
		public MemoryReference[] MemoryReferences;
		public List<ExternalReference> IncomingReferences;
		public List<ExternalReference> OutgoingReferences;

		public MethodBody( uint address, uint length, Instruction[] instructions )
		{
			this.Name = string.Format( "sub_{0:X8}", address );
			this.TotalLines = length / 4;

			this.Address = address;
			this.Length = length;

			this.IncomingReferences = new List<ExternalReference>();
			this.OutgoingReferences = new List<ExternalReference>();

			if( instructions != null )
				this.Populate( instructions );
		}

		public void Populate( Instruction[] instructions )
		{
			this.Instructions = instructions;

			// - determine locals (loop for first addiu $sp, $sp, [size]
			// - find all labels (branch targets)

			bool foundSpMod = false;
			List<Label> labels = new List<Label>();
			List<CodeReference> codeRefs = new List<CodeReference>();
			List<MemoryReference> memRefs = new List<MemoryReference>();
			uint[] currentRegisters = new uint[ 32 ];
			uint validRegisters = 0;
			foreach( Instruction instruction in instructions )
			{
				if( instruction.IsBranch == true )
				{
					uint target = 0;
					foreach( Operand op in instruction.Operands )
					{
						if( op.Type == OperandType.BranchTarget )
						{
							target = ( uint )( ( int )instruction.Address + 4 + op.Immediate );
							break;
						}
					}
					if( target > 0 )
						this.AddLabelReference( labels, instruction, target );

					// TODO: allow some to fall through the branch?
					validRegisters = 0;
				}
				else if( instruction.IsJump == true )
				{
					uint target = 0;
					foreach( Operand op in instruction.Operands )
					{
						if( op.Type == OperandType.JumpTarget )
						{
							target = ( uint )op.Immediate;
							break;
						}
					}
					if( ( target >= this.Address ) && ( target < ( this.Address + this.Length ) ) )
						this.AddLabelReference( labels, instruction, target );
					else
						this.AddCodeReference( codeRefs, instruction, target );
					validRegisters = 0;
				}
				else if( instruction.IsLoad == true )
				{
					int reg1 = instruction.Operands[ 1 ].Register.Ordinal;
					if( ( validRegisters & ( 1 << reg1 ) ) > 0 )
					{
						uint target = currentRegisters[ reg1 ];
						target = ( uint )( ( int )target + instruction.Operands[ 1 ].Immediate );
						this.AddMemoryReference( memRefs, instruction, target, true );
					}
				}
				else if( instruction.IsStore == true )
				{
					int reg1 = instruction.Operands[ 1 ].Register.Ordinal;
					if( ( validRegisters & ( 1 << reg1 ) ) > 0 )
					{
						uint target = currentRegisters[ reg1 ];
						target = ( uint )( ( int )target + instruction.Operands[ 1 ].Immediate );
						this.AddMemoryReference( memRefs, instruction, target, false );
					}
				}
				if( ( foundSpMod == false ) && ( instruction.Opcode.InstructionEntry.Name == "addiu" ) )
				{
					foundSpMod = true;
					int adjustment = instruction.Operands[ 2 ].Immediate / 4;
					this.LocalsSize = -adjustment;
				}
				else
				{
					uint flags = instruction.Opcode.InstructionEntry.Flags;
					if( instruction.Opcode.InstructionEntry.Name == "lui" )
					{
						int reg = instruction.Operands[ 0 ].Register.Ordinal;
						validRegisters |= ( uint )( 1 << reg );
						currentRegisters[ reg ] = ( uint )instruction.Operands[ 1 ].Immediate << 16;
					}
					else if( ( flags & InstructionTables.OUT_RT ) > 0 )
					{
						if( instruction.Opcode.InstructionEntry.Name == "addiu" )
						{
							int reg1 = instruction.Operands[ 1 ].Register.Ordinal;
							if( ( validRegisters & ( 1 << reg1 ) ) > 0 )
							{
								int reg2 = instruction.Operands[ 0 ].Register.Ordinal;
								validRegisters |= ( uint )( 1 << reg2 );
								currentRegisters[ reg2 ] = ( uint )( ( int )currentRegisters[ reg1 ] + instruction.Operands[ 2 ].Immediate );
							}
						}
						else if( instruction.Opcode.InstructionEntry.Name == "ori" )
						{
							int reg1 = instruction.Operands[ 1 ].Register.Ordinal;
							if( ( validRegisters & ( 1 << reg1 ) ) > 0 )
							{
								int reg2 = instruction.Operands[ 0 ].Register.Ordinal;
								validRegisters |= ( uint )( 1 << reg2 );
								currentRegisters[ reg2 ] = currentRegisters[ reg1 ] | ( uint )instruction.Operands[ 2 ].Immediate;
							}
						}
						else
						{
							// Changed - no longer valid
							int reg = instruction.Operands[ 0 ].Register.Ordinal;
							validRegisters &= ~( uint )( 1 << reg );
						}
					}
				}

				//lui $n, NNN
				//addiu $n, $n, NNN

				//lui $n, NNN
				//ori $n, $n, NNN

				//lui $n, NNN
				//l* $m, NNN($n)

				//lui $n, NNN
				//s* $m, NNN($n)
			}

			// Sort all
			this.SortAndSet( labels, codeRefs, memRefs );
		}

		private void SortAndSet( List<Label> labels, List<CodeReference> codeRefs, List<MemoryReference> memRefs )
		{
			labels.Sort( delegate( Label a, Label b )
			{
				return a.Address.CompareTo( b.Address );
			} );
			this.Labels = labels.ToArray();
			codeRefs.Sort( delegate( CodeReference a, CodeReference b )
			{
				return a.Address.CompareTo( b.Address );
			} );
			this.CodeReferences = codeRefs.ToArray();
			memRefs.Sort( delegate( MemoryReference a, MemoryReference b )
			{
				return a.Address.CompareTo( b.Address );
			} );
			this.MemoryReferences = memRefs.ToArray();
		}

		private void AddLabelReference( List<Label> labels, Instruction instruction, uint target )
		{
			foreach( Label label in labels )
			{
				if( label.Address == target )
				{
					label.References.Add( instruction );
					return;
				}
			}
			Label newLabel = new Label();
			newLabel.Name = string.Format( "loc_{0:X8}", target );
			newLabel.Address = target;
			newLabel.References.Add( instruction );
			labels.Add( newLabel );
		}

		private void AddCodeReference( List<CodeReference> codeRefs, Instruction instruction, uint target )
		{
			foreach( CodeReference codeRef in codeRefs )
			{
				if( codeRef.Address == target )
				{
					codeRef.References.Add( instruction );
					instruction.Reference = codeRef;
					return;
				}
			}
			CodeReference newCodeRef = new CodeReference();
			newCodeRef.Address = target;
			newCodeRef.References.Add( instruction );
			newCodeRef.Instruction = instruction;
			instruction.Reference = newCodeRef;
			codeRefs.Add( newCodeRef );
		}

		private void AddMemoryReference( List<MemoryReference> memRefs, Instruction instruction, uint target, bool isRead )
		{
			//Debug.WriteLine( string.Format( "adding memory reference at {0:X8} ({1}) to {2:X8} for {3}", instruction.Address, instruction, target, isRead ? "read" : "write" ) );
			foreach( MemoryReference memRef in memRefs )
			{
				if( memRef.Address == target )
				{
					memRef.References.Add( instruction );
					if( isRead == true )
						memRef.Reads++;
					else
						memRef.Writes++;
					instruction.Reference = memRef;
					return;
				}
			}
			MemoryReference newMemRef = new MemoryReference();
			newMemRef.Address = target;
			newMemRef.References.Add( instruction );
			if( isRead == true )
				newMemRef.Reads++;
			else
				newMemRef.Writes++;
			newMemRef.Instruction = instruction;
			instruction.Reference = newMemRef;
{'fraction_non_alphanumeric': 0.13773685412069098, 'fraction_numerical': 0.0066205007229282395, 'mean_word_length': 2.580926430517711, 'pattern_counts': {'":': 0, '<': 54, '<?xml version=': 0, '>': 43, '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': '6032786', 'n_tokens_mistral': 5099, 'n_tokens_neox': 3846, 'n_words': 1005}