This video demonstrates how to implement a VirtualAddress struct in Rust for a debugger, covering key concepts including: (1) the program counter (RIP register) stores virtual addresses of executing instructions, (2) implementing arithmetic operations (+, -, +=, -=) using Rust's std::ops traits with wrapping methods to prevent precision loss, (3) deriving comparison operators (==, !=, >, <, >=, <=) through PartialOrd and PartialEq traits, and (4) creating a safe interface to read register values and construct VirtualAddress objects from them.
Implementing Virtual Addresses and Instruction Pointer in Rust Debugger
Added:after the code that we wrote in the previous video, uh we can start reading registers through the CLI and we can even start reading the program counter.
So program counter is a special register and it points to the uh current instruction being executed in a program and uh it doesn't actually point to it.
It stores its virtual address. We'll get to virtual addresses and how to play around with the virtual addresses. we'll need to create a strct that can represent it. So we'll read the virtual address and create an object out of that strct and uh we'll it it will basically be a wrapper around the virtual address and we'll add some methods to it so that we can do uh some basic manipulation. Okay. So I'll create that file in RDB.
So let me close this.
So we'll cd into source and then RDB and right here I will create the file called virtual address rs and okay so right here we want to create a strct so we'll call it virtual address itself. So pubstruct and it needs to be public. So pubstruct uh virt let's just call it virtual address and so the address uh the virtual address is basically uh u64. So we'll create a field address underscore and we'll give it a type of U64 and uh we'll create uh create constructor for it and uh so let's do that fn new and we need to return a self self from it.
So this will be a default virtual address and its value will be zero.
Adder equal to zero but if we know the value then I need another kind of constructor. So pub fn let's call it with adder and it takes an adder of type it's going to be u64 and it's going to return a self and so self and let's adder will be equal to the adder that we passed And uh we also need a getter function.
So to be able to get the value out of the address. So pub fn and it takes a self and we return self dot adder from it.
We'll write uh syntax error. Oh, sorry, my bad.
Uh, this is the right syntax, right?
And uh I guess this is not working because we haven't added to the mod ar.
So let me open CD.
So in here we need to add the virtual address as well.
So pub mod virtual address right quit.
Wait, let's open it again and see virtual address. Yeah, so the syntax highlighting works. What's the issue?
Oh, so I'm not returning. I didn't specify the return type. Uh, it's going to return uh U64.
All right.
And uh since we want to play around with this address uh we should implement some methods uh we want to do standard operations on virtual addresses like I want to increment a virtual address decrement it and we need to be able to compare this the object of this truck with other objects of this truck. So we want to basically override the operators. So the equal to operator greater than greater than equal to. If this code were in Java, I would tell you to implement the comparable and iterable interfaces for this class. But in Rust, we don't have that. We What is it saying? Try adding impul default for virtual address.
So we'll do that as well.
Uh let's imple default for uh virtual address and fn default and let's call self new in this and that will return the new object.
All right. Uh as I said if I this were Java I would want you to implement the comparable and the comparator interfaces. Uh we don't have that in Rust. We instead have other uh traits that we can implement. So we'll do that.
The first thing we need to do is uh as as I said we want to uh increment decrement these operators.
We want basically those operators to be overridden for this truck. So we'll start doing that. Uh let's impel std ops and we'll implement the add operator for it and it takes an i64 because we can possibly give it a negative value. In that case it will uh decrement. So we'll implement it for virtual adder and from this uhhuh so in this we have to implement the add function and this add function takes a self and an offset.
The offset is i64 as I said and it returns a new virtual address. So virtual address virtual address with uh adder and to it I pass uh-huh self dot adder uh need to type cast it to I64 and then add the offset as U64 type casted back and it expects an item.
Oh, sorry.
Uh not all trade items implemented. It's missing the output. Implement the missing item. Type output. Oh, so we need to give it a type. We need to define the type as well. So type output equals to it's just going to return a virtual header.
And it expects a semicolon.
And that's it. That will override the addition operator for us. My bad guys, we shouldn't be doing this. This will cause precision issues. So what will happen is uh since we type casted to i64 and then type casted back to U64, that will cause some uh precision loss in case of high numbers because max of U64 is way greater than max of I64. So we should not be doing this. instead uh Rust has that functionality built in. It allows us to uh add I64 through self dot adder uh underscore dot. We can call the wrapping uh add this function signed and to this we can pass in the signed integer instead.
So the signed uh integer for us is the offset and uh that will handle the wrapping around value like so it won't cause precision loss. This method won't do that. So we can write it back and so that implemented the add for us but we also need to implement the subtract.
So wait a minute let me just copy all of this. So that's 1 2 3 4 5 6. So 6 5 and then P and instead of add uh we'll implement the sub for virtual adder and uh the type remains same but instead of add here we have the sub function like so and instead of wrapping add signed we'll call the wrapping subs signed wrapping subsigned the rest everything remains the same and I can remove this.
So that handles the plus operator for us.
This handles the minus for us. But I also want the plus wait the plus equal to and the minus equal to.
So for plus equal to uh we can implement the add assign trait. So let's copy six lines again.
Six y paste it.
Yeah. And instead of sub let's implement add assign.
And instead of sub uh we it this has add assign function and uh instead of creating a new object we will update the existing object. So self dot adder equal to doesn't it need to be mutable?
Yeah. So in that case self needs to be mutable.
So let's do that mute and uh I guess rest everything remains.
Type output is not a member. So we can remove this.
Let's write this and uh mismatch types expected virtual adder. It doesn't return a virtual adder. Uh it doesn't return anything. We are updating the existing object, right?
So we can remove this as well.
Remove this. And so that's add a sign for us. But we also want the subtract a sign. So 1 2 3 4 5 5 Y and then let's come and paste it here. So instead of add assign I want to implement now the sub assign and instead of add here it will be sub it will be mutable and oh my bad guys this here needs to be add signed and this here needs to be sub signed and add a semicolon here we're not returning anything so add a semicolon huh So now I also want to implement other operators that is basically for comparison. I want the equal to equal to operator implemented.
Basically double equal to new displays it like this once two solid lines. I also want the not equal to operator and I also want uh so that an object is reflexive basically a equal to equal to a should be true and we want the following.
Oh my god.
I want the not equal to operator. I want the object to be reflexive as in a should be equal to a.
Then I want uh the greater than the less than the greater than equal to operators and the less than equal to operators to work for me.
Uh all of this can be done by simply deriving all of these for the strct.
So all these operators work through simple derivation. But we can uh we can also add one more thing that is basically in Java you have that dot equal to function right. You can add a similar thing in rust. In rust we have the cmp which is basically compare and you can also derive that through the uh odd was it odd? Let me check. Ah yes by uh deriving odd for our strct and uh partial odd is what gives us these greater than less than greater than equal to less than equal to functions.
So what we can do here is come up to our strct uh right here and we can uh derive we'll derive uh partial EQ EQ partial odd and odd uh unmatched brace.
All right. So, let me try to build it once. Cargo build.
So, it built fine. Uh we are doing all of this uh rigomearroll to be able to read the instruction pointer register and create an object of this truck that we created. this virtual address strct and uh we'll do that in uh the process.
So let me add a function to create this object. So let's go to process and at the end of it we'll implement a function basically that will be creating the object of virtual address from the RIP register which is instruction pointer register and let's call it the program count uh it's also called program counter colloquy.
So we'll create a function called pub unsafe fn uh get instruction pointer pointer VA for virtual address and it takes a mutable of self and uh it will return a result of v virtual address comma and in case of error we'll return a string saying we could not retrieve the instruction pointer and in here what we'll do is we'll extract uh we need to get the value of the rip register So let rip val equal to self dot procre registers dot get register val by id and in this id we'll pass in the id of the rip register uh so register id of uh rip that's the ID of the instruction pointer register and then we'll unwrap it.
All right.
Uh let's match on this rip val and uh what does this return actually?
GD. This returns a result of register value.
it returns a result of register value.
Okay.
So for the RIP register we expect a U64 from it so that we can create a virtual address.
So if we get a register value of U64 then we're good in that case. Uh what I can do is create the object of virtual address and we know virt uh with adder and to this I will pass uh the val that we have uh otherwise if we didn't get this we'll return an error saying invalid register value returned register value returned and uh this will return a result. All right. So let's try to write it.
Let's try to build it.
Cargo build.
It works fine. I guess we won't know it until we test. So to be able to test this, let's go to the main function uh main RS and in here uh whenever we do control D, we will also print the virtual address so that the user is able to see at what address what was the instruction being executed when they stopped the debugger.
So what you can do is uh get wait a minute process it is unsafe right? Yeah. So in here we need to make it unsafe and when we say exiting debugger uh we will also print the value of the instruction pointer.
So let uh instruction pointer be equal to process dot get instruction pointer virtual address and if let okay of virtual address equal to IP in that case uh let's print len along this Okay.
And let's also print line the virtual address.
Uh va it's an object of virtual adder. So dot uh the getter was called adder right here.
Adder.
Let's write and quit. Let's see if it works. Cargo build.
I guess it does. Now let's try to run it. Cargo run. Yes.
So our debugger is running right now and when I press Ctrl D it prints the virtual address of the instruction pointer. So that's what we wanted to do.
So right now our code is uh correctly reading the value of the instruction pointer and creating an an object of the virtual address out of it. So that's it for this video. We will start playing around with these virtual addresses going forward. And that's it. I'll see you in the next one.
Up Next

ELF Binary Structure: A Comprehensive Guide for Cybersecurity Analysis and Reverse Engineering
@PinkDraconian
12.1K views•2021-02-19

Solving the Heat Equation with DeepXDE and PINNs
@Dr.Mohammad_Samara
8.5K views•2023-07-17

HTTP Requests Explained: GET, POST, PUT, DELETE
@codecademy
103.1K views•2021-10-07

Enigma Machine Mechanics: WWII Encryption Explained
@JaredOwen
13.2M views•2021-12-11
Related Study Plans & Knowledge Roadmaps
Structured learning paths in Computer Science






















![Calling conventions and single-step execution - 16-bit Intel x86 breadboard computer [part 5]](https://i.ytimg.com/vi/O73qC3VFngA/sddefault.jpg)
















