-
Notifications
You must be signed in to change notification settings - Fork 71
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[StackAnalyzer] Analyze the static Stack for composite. #486
base: main
Are you sure you want to change the base?
Conversation
Feature/dag
clean the code.
@@ -0,0 +1,36 @@ | |||
import unittest # The test framework | |||
import sys | |||
sys.path.insert(0, '/home/minghwu/work/StackAnalyzer/pyelftool_parser/src') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel that we may better use a relative path here
## test printc | ||
self.assertEqual(self.stacklist[12], -416) | ||
if __name__ == '__main__': | ||
path = "./tests.unit_pingpong.global.ping" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe we should remove the part between the if statement and unittest.main(). They are duplicated with setUp(self) above
Add mao's composite to my own.
@@ -0,0 +1,203 @@ | |||
import sys |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that you likely want the entire pyelftool to be in tools/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure why I try to merge from my own repo. Then it keeps moving it to main folder. I think it is my command line problems. We could move it afterward after we decide how to integrate with system.
pc_flag = 1 | ||
if (pc_flag == 1): ## catch the point until the next symbol, means it is exit point. | ||
self.exit_pc = i.address | ||
log(f'0x{i.address:x}:\t{i.mnemonic}\t{i.op_str}') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't run this, but does this log quite a bit to stdout/err? We'd like the output to be relatively quiet in most cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, there is a debug.py. It is actually a log system. We could decide what level log to stdout.
self.entry_pc = symbol['st_value'] | ||
log("Set up entry point") | ||
log(hex(self.entry_pc)) | ||
if(symbol.name == 'custom_acquire_stack'): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Am I understanding correctly that you don't treat the __cosrt_s_*
symbols as entry points? Is the logic that they each call custom_acquire_stack
, so it is OK to start tracing from there? That might miss some stack operations. I think that __cosrt_upcall_entry
also uses that symbol, so you might do redundant computations.
I'm likely just missing something here ;-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for that. I just test the __cosrt_upcall_entry. I will give it a look.
if self.register.reg["pc"] in self.symbol.keys(): ## check function block (as basic block but we use function as unit.) | ||
self.stackfunction.append(self.symbol[self.register.reg["pc"]]) | ||
logstack(self.symbol[self.register.reg["pc"]]) ## TODO: here is error. | ||
self.register.updatestackreg(self.symbol[self.register.reg["pc"]] == 'custom_acquire_stack') ## if it is acquiring stack address, do not setting the stack size. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't follow a lot of this logic. Not sure why a stackfunction is doing operations with the pc, or why the pc indexes a symbol correctly. I'm just having a hard time following all of this, which means I likely can't give a useful review.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will try to fix the comment here. The comments is misleading. I did not notice that. Thank you for giving the ideas of it. But the idea is that I will calculate the stack size whenever we jump or flow to a new function block. I track how much the stack pointer changed, and I store the changing into an array.
|
||
#### set up next instruction pc | ||
|
||
if (self.index == index_list.index(self.register.reg["pc"])): ## fetch next instruction |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is all quite a bit more complicated than I was expecting. Great job figuring it all out!
self.stackfunction.append(self.symbol[self.register.reg["pc"]]) | ||
logstack(self.symbol[self.register.reg["pc"]]) ## TODO: here is error. | ||
self.register.updatestackreg(self.symbol[self.register.reg["pc"]] == 'custom_acquire_stack') ## if it is acquiring stack address, do not setting the stack size. | ||
self.stacklist.append(self.register.reg["stack"]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We found an API in the library that told you if an instruction modifies stacks. Is this the API? I'm looking through here trying to find the stack logic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, there is Executor(executor.py). I pass each instruction into it. And I use capstone to check if it is modifing the rsp. There is a "flagrsp" in executor to check it.
############################################ | ||
##------------------------------------------ | ||
## execute stage. | ||
if flagrsp: ## if rsp is in the instruction |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't there a part of the API that tells you if an instruction modifies the stack? Aren't those the only instructions you need to worry about?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I use capstone's "(regs_read, regs_write) = inst.regs_access()". Check that is it reading/writing rsp? This regs_access can also specify the implication read/write rsp.
src/composer/src/main.rs
Outdated
sys.add_objs_iter(&c_id, ElfObject::transition_iter(c_id, &sys, &mut build)?); | ||
sys.add_invs_iter(&c_id, Invocations::transition_iter(c_id, &sys, &mut build)?); | ||
println!("path:{}", obj.get_path()); | ||
let output = Command::new("python3") | ||
.arg("/home/minghwu/work/minghwu/composite/pyelftool_parser/src/analyzer.py") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You'll want to use relative paths here so that you can avoid hardcoding the absolute path.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this is indeed a problem. I do not figure out how to put into tools. Therefore, I put absolute path for this moment. I will fix it afterward. Thank you for pointing out.
src/composer/src/main.rs
Outdated
sys.add_objs_iter(&c_id, ElfObject::transition_iter(c_id, &sys, &mut build)?); | ||
sys.add_invs_iter(&c_id, Invocations::transition_iter(c_id, &sys, &mut build)?); | ||
println!("path:{}", obj.get_path()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unless a print is for a specific purpose (other than debugging), we don't want to add them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh sorry. It is a debugging mistake.
} else { | ||
let stderr = String::from_utf8_lossy(&output.stderr); | ||
eprintln!("Script error: {}", stderr); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For all of this, we'll want to add a pass. This is likely in your other code, so I'm hesitate to say much here.
I'd like to understand a couple of things:
|
Summary of this Pull Request (PR)
Add description here.
Intent for your PR
Choose one (Mandatory):
Reviewers (Mandatory):
(Specify @<github.com username(s)> of the reviewers. Ex: @user1, @user2)
Code Quality
As part of this pull request, I've considered the following:
Style:
Code Craftsmanship:
Testing
I've tested the code using the following test programs (provide list here):