| View previous topic :: View next topic |
| Author |
Message |
hnaves
Joined: 03 Feb 2009 Posts: 30
|
Posted: Tue May 12, 2009 8:43 pm Post subject: PSP decompiler |
|
|
While trying to decompile the usb.prx (FW 1.5) by hand, I realized that it was a very long and boring process... So I made this little tool to help us while doing some prx reverse engineering...
http://ifile.it/93pthb0
The instructions to compile and use are in the README file.The output of the program is a low-level "C" program (with a lot of imperfections), but it is almost understandable. There is also a DOT mode, where the output is a collection of graphviz dot files with the control flow graph of the program.
I know that this tool has several bugs and improvements to be made, and I hope that more people contribute to its development. Please use with caution. I would like to thank Tyranid for the development of prxtool. |
|
| Back to top |
|
 |
hlide
Joined: 10 Sep 2006 Posts: 750
|
Posted: Wed May 13, 2009 5:29 am Post subject: |
|
|
quite impressive
do you think we can put it through SVN in google code ? so some of use can contribute ? |
|
| Back to top |
|
 |
jimparis
Joined: 10 Jun 2005 Posts: 1179 Location: Boston
|
Posted: Wed May 13, 2009 5:43 am Post subject: |
|
|
| Agreed, very impressive! |
|
| Back to top |
|
 |
TyRaNiD
Joined: 18 Jan 2004 Posts: 918
|
Posted: Wed May 13, 2009 6:06 am Post subject: |
|
|
| Nice work :) |
|
| Back to top |
|
 |
hnaves
Joined: 03 Feb 2009 Posts: 30
|
Posted: Wed May 13, 2009 7:31 am Post subject: |
|
|
Does anybody here uses GIT? My project is already under version control at http://repo.or.cz/w/pspdecompiler.git. I believe GIT is better and easier than SVN or CVS, and it is used in the Linux Kernel project :-)
I have also another project, that is to build an OPEN EDITION USB driver for PSP. I have already started, and decompiled (by hand :-) about 20% of the original PRX. Using the tool now will greatly improve the speed of the development. Anybody interested? |
|
| Back to top |
|
 |
ghost_gluck

Joined: 04 Apr 2008 Posts: 7
|
Posted: Wed May 13, 2009 9:13 am Post subject: |
|
|
| hnaves wrote: | | I have also another project, that is to build an OPEN EDITION USB driver for PSP. I have already started, and decompiled (by hand :-) about 20% of the original PRX. Using the tool now will greatly improve the speed of the development. Anybody interested? |
Nice work!
I find some bugs with firmware prxses decompilation (usb.prx and other) and fix it, see below
| Code: | diff -urN pspdecompiler/lists.c pspdecompiler.patched/lists.c
--- pspdecompiler/lists.c 2009-05-12 13:29:26.000000000 +0300
+++ pspdecompiler.patched/lists.c 2009-05-13 11:24:32.812500000 +0300
@@ -85,7 +85,7 @@
element list_head (list l)
{
- return l->head;
+ return (l != NULL) ? l->head : NULL;
}
void *list_headvalue (list l)
@@ -200,22 +200,23 @@
void *element_getvalue (element el)
{
- return el->value;
+ return (el != NULL) ? el->value : NULL;
}
void element_setvalue (element el, void *val)
{
- el->value = val;
+ if(el != NULL )
+ el->value = val;
}
element element_next (element el)
{
- return el->next;
+ return (el != NULL) ? el->next : NULL;
}
element element_previous (element el)
{
- return el->prev;
+ return (el != NULL) ? el->prev : NULL;
}
diff -urN pspdecompiler/operations.c pspdecompiler.patched/operations.c
--- pspdecompiler/operations.c 2009-05-12 13:29:26.000000000 +0300
+++ pspdecompiler.patched/operations.c 2009-05-13 13:37:12.140625000 +0300
@@ -161,7 +161,7 @@
}
case I_MOVN:
val = element_getvalue (element_next (list_head (op->operands)));
- if (val->val.intval == 0) {
+ if (val != NULL && val->val.intval == 0) {
reset_operation (op);
op->type = OP_NOP;
}
diff -urN pspdecompiler/output.c pspdecompiler.patched/output.c
--- pspdecompiler/output.c 2009-05-12 13:29:26.000000000 +0300
+++ pspdecompiler.patched/output.c 2009-05-13 13:43:22.296875000 +0300
@@ -462,7 +462,7 @@
val = list_headvalue (op->operands);
if (val->type == VAL_SSAVAR) {
if (val->val.variable->type == SSAVAR_CONSTANT) {
- address = val->val.variable->type;
+ address = val->val.variable->info;
val = list_tailvalue (op->operands);
address += val->val.intval;
fprintf (out, "*((%s) 0x%08X)", type, address);
|
Problem with access to the structure member when pointer to val or el struct is NULL.
Mabye you are already fix this problem. I don't check git source.
[offtopic]
About OPEN EDITION USB driver for PSP:
So I started working on USB driver for PSP. I want to add to the driver functionality which allow create more than Block Devices, for example: HID devices (joysticks etc), RNDIS devices and additional host functionality (PSP as USB Host - maybe this is a dream).
I want try to connect my GPS (PSP-290) module to PC for examine communication protocol. If GPS module connected to PC and it is works as device, then PSP works as host when GPS module was connected to PSP.(IMHO) It's correct?
[/offtopic]
EDIT:
I find bug with translation addresses, see below:
lui $t0, 0xbc10
lw $t1, 0x4c($t0)
is interpreted as var = *((int*) 0x00000050, but right translation is var = *((int*) 0x0xbc10004c.
EDIT:
previous bug was fixed. see diff. problem in address = val->val.variable->type, but base address value contains in val->val.variable->info
New problem. Procedure calls through registers (jal rX) doesn't reverses correctly. Maybe its possible because subroutine address calculation mechanism doesn't implemented/works incorrectly. _________________ Sorry for terrible english. My native language is C++... |
|
| Back to top |
|
 |
sauron_le_noir
Joined: 05 Jul 2008 Posts: 229
|
Posted: Thu May 14, 2009 2:48 am Post subject: |
|
|
| Great tool Where can we found nidsfiles ? are this files compatible with the nids file found on http://silverspring.lan.st/ |
|
| Back to top |
|
 |
ghost_gluck

Joined: 04 Apr 2008 Posts: 7
|
Posted: Thu May 14, 2009 3:15 am Post subject: |
|
|
| sauron_le_noir wrote: | | Great tool Where can we found nidsfiles ? are this files compatible with the nids file found on http://silverspring.lan.st/ |
compatible. _________________ Sorry for terrible english. My native language is C++... |
|
| Back to top |
|
 |
hlide
Joined: 10 Sep 2006 Posts: 750
|
Posted: Thu May 14, 2009 7:19 am Post subject: |
|
|
some suggestions :
1) prepend "int " to "varN = ..." :
in "static void print_binaryop (FILE *out, struct operation *op, const char *opsymbol, int options)",
"void print_complexop (FILE *out, struct operation *op, const char *opsymbol, int options)", etc. transform every "print_value (out, list_headvalue (op->results));" into "print_result (out, list_headvalue (op->results));"
and add :
| Code: |
void print_result(FILE *out, struct value *val)
{
fprintf(out, "int ");
print_element (out, value, 0);
}
|
2) add ';' to each output asm string instruction :
| Code: |
static
void print_asm (FILE *out, struct operation *op, int identsize, int options)
{
struct location *loc;
ident_line (out, identsize);
fprintf (out, "__asm__ (");
for (loc = op->info.asmop.begin; ; loc++) {
if (loc != op->info.asmop.begin) {
fprintf (out, "\n");
ident_line (out, identsize);
fprintf (out, " ");
}
fprintf (out, "\"%s;\"", allegrex_disassemble (loc->opc, loc->address, FALSE));
if (loc == op->info.asmop.end) break;
}
if (list_size (op->results) != 0 || list_size (op->operands) != 0) {
print_asm_reglist (out, op->results, identsize, options);
if (list_size (op->operands) != 0) {
print_asm_reglist (out, op->operands, identsize, options);
}
}
fprintf (out, ");\n");
}
|
i'm not sure there is a good reason to handle $sp and load/store operations with $sp as base as they are prolog and epilog, so you may probably drop them or rather make them into comment. By the way, having varN in epilog is ackward : wouldn't it better not to ssa them ?. |
|
| Back to top |
|
 |
hnaves
Joined: 03 Feb 2009 Posts: 30
|
Posted: Fri May 15, 2009 8:48 am Post subject: |
|
|
Hi,
I have corrected several bugs including those posted by ghost_gluck, and among them are:
- Invalid detection of nested ifs gotos;
- Better detection of constants
- Detection of callbacks
To checkout the lastest snapshot, please refer to
http://repo.or.cz/w/pspdecompiler.git
and click on the first snapshot right below the shortlog (on the very right side of the page)
The next step is to improve the detection of arguments and return values of subroutines |
|
| Back to top |
|
 |
willow :--)
Joined: 13 Jan 2007 Posts: 126
|
Posted: Fri May 15, 2009 10:38 am Post subject: |
|
|
This looks great!
You might want to remove the pdf documents from the repository though, I believe you can't freely distribute those ;)
Also, a very minor point, but could it be possible to have the list of options in alphabetical order in the "usage" text? (because there are lots of options)
| Code: |
" -c output code\n"
" -d print the dominator\n"
" -e print edge types\n"
" -f print the frontier\n"
" -g output graphviz dot\n"
" -i print prx info\n"
" -n specify nids xml file\n"
" -q print code into nodes\n"
" -r print the reverse depth first search number\n"
" -s print structures\n"
" -t print depth first search number\n"
" -v increase verbosity\n"
" -x print the reverse dominator\n"
" -z print the reverse frontier\n",
|
|
|
| Back to top |
|
 |
SilverSpring
Joined: 27 Feb 2007 Posts: 115
|
Posted: Fri May 15, 2009 5:49 pm Post subject: |
|
|
Very nice, you worked out the new-style prxs? Good work. _________________ PSP PRX LibDocs |
|
| Back to top |
|
 |
hlide
Joined: 10 Sep 2006 Posts: 750
|
|
| Back to top |
|
 |
hlide
Joined: 10 Sep 2006 Posts: 750
|
Posted: Sat May 16, 2009 7:22 pm Post subject: |
|
|
@hnaves
There is a problem : in a loop starting with "while (1)" with a register counter, i have : "varN = varN;" instead of "varJ = varI + CONSTANT;" where varI is containing a constant. It seems the issue is in output.c :
| Code: |
void print_operation (FILE *out, struct operation *op, int identsize, int options)
{
...
if ((op->status & (OP_STAT_CONSTANT | OP_STAT_DEFERRED)) == OP_STAT_CONSTANT) {
struct value *val = list_headvalue (op->results);
if (!(options & OPTS_NORESULT)) {
print_value (out, val, OPTS_RESULT);
fprintf (out, " = ");
}
print_value (out, val, 0);
} else {
...
}
|
I may be wrong but it looks as if when an SSA register simplified to a constant" the operation status is erroneously marked as OP_STAT_CONSTANT because it doesn't take into account the fact that this operation is inside a loop and is not invariant.
If not, it means an I_ADDIU is wrongly transformed into a I_MOVE. |
|
| Back to top |
|
 |
D_Street
Joined: 12 Jun 2008 Posts: 22 Location: Berkeley, CA
|
Posted: Sat May 16, 2009 8:40 pm Post subject: |
|
|
really nice work!
i remember last year i also did a little decompiler, but that was a bit lame, i just did the decompile thing out of the output from prxtool! i guess that way i can just copy & paste a piece of the disassembly output and decompile it without any problems. |
|
| Back to top |
|
 |
hlide
Joined: 10 Sep 2006 Posts: 750
|
Posted: Sun May 17, 2009 2:18 am Post subject: |
|
|
| there is a regression on the last version, pspdecompiler crashes on some prx files whereas the first public version did not. |
|
| Back to top |
|
 |
hnaves
Joined: 03 Feb 2009 Posts: 30
|
Posted: Sun May 17, 2009 10:50 am Post subject: |
|
|
| Could you provide me the prx name (and version)? There were several critical bugs fixed (in the constant propagation algorithm) in the last revision, maybe the incorrect output for loops with constants will not exist anymore. |
|
| Back to top |
|
 |
hlide
Joined: 10 Sep 2006 Posts: 750
|
Posted: Sun May 17, 2009 11:05 am Post subject: |
|
|
I tried your last revision : two comile-time errors about value_append function missing the last argument in ssa.c; I appended FALSE as last argument to build pspdecompiler fine.
And yes, I have no crash now with all the prx which crashed.
Last edited by hlide on Sun May 17, 2009 10:04 pm; edited 1 time in total |
|
| Back to top |
|
 |
hlide
Joined: 10 Sep 2006 Posts: 750
|
Posted: Sun May 17, 2009 9:59 pm Post subject: |
|
|
do you detect some functions not terminating with a JA $RA but with a J ?
the rule is to check if a subroutine has no forward conditional branch when you meet a J to conclude this is subroutine with a tail call to another subroutine :
| Code: |
void X() { ...; Y(); } <=> ...; J sub_Y; ...;
void Y() { ... } <=> ...: JR $RA; ...;
int Z() { ...; return W(); } <=> ...; J sub_Y; ...;
int W() { ... } <=> ...; JR $RA; ...;
|
|
|
| Back to top |
|
 |
hlide
Joined: 10 Sep 2006 Posts: 750
|
Posted: Sun May 17, 2009 11:18 pm Post subject: |
|
|
bug with counters in loops is still unresolved :
| Code: |
while (1) {
var17 = var17; <-- it should be : "var17 = var17 + 0x00000001;"
InterruptManagerForKernel_7527A9BA (0x00000019, 0x00000000, 0x00000001);
if (((var17 < 0x00000010)) != 0x00000000)
continue;
break;
}
|
"var17 = var17;" is output when executing output.c:593 :
| Code: |
if ((op->status & (OP_STAT_CONSTANT | OP_STAT_DEFERRED)) == OP_STAT_CONSTANT) {
struct value *val = list_headvalue (op->results);
if (!(options & OPTS_NORESULT)) {
print_value (out, val, OPTS_RESULT);
fprintf (out, " = ");
}
print_value (out, val, 0);
} else {
|
first, i think "print_value (out, val, 0);" should be something like : "print_expression (out, <operands_expression>, 0, 0);"
second, i tracked OP_STAT_CONSTANT and found out they are set in constant.c:110 (I_MOV), 118(I_ADDI[U]), 124(I_OR). They are trying to make a constant value having the result. The issue var17 is initially set to 0 and so it is a constant. When it tries to evaluate "var17 = I_ADDIU(var17, 1)" it will set var17 as being a constant 1. So var17 is wrongly set as a constant operation :/ and we get "var17 = var17".
so when I try to remove lines constant.c:83-88, I get :
| Code: |
while (1) {
var17 = 0x00000000 + 0x00000001;
InterruptManagerForKernel_7527A9BA (0x00000019, 0x00000000, 0x00000001);
if (0x00000001 != 0x00000000)
continue;
break;
}
|
as I feared, still not good. |
|
| Back to top |
|
 |
hnaves
Joined: 03 Feb 2009 Posts: 30
|
Posted: Wed May 20, 2009 9:59 am Post subject: |
|
|
Hi hlide,
I believe that the problem is fixed now. |
|
| Back to top |
|
 |
hlide
Joined: 10 Sep 2006 Posts: 750
|
Posted: Thu May 21, 2009 3:52 am Post subject: |
|
|
| ackonwledged. I'll try when i have time and when I'm getting familiar with GIT :/ (which action you should do like a Update SVN ?) |
|
| Back to top |
|
 |
hnaves
Joined: 03 Feb 2009 Posts: 30
|
|
| Back to top |
|
 |
hlide
Joined: 10 Sep 2006 Posts: 750
|
Posted: Thu May 21, 2009 5:22 am Post subject: |
|
|
When doinga "pull", I got this :
| Code: |
git.exe pull "origin"
remote: Compressing objects: 100% (17/17) [K
remote: Compressing objects: 100% (17/17), done.[K
remote: Total 26 (delta 13), reused 22 (delta 9)[K
From git://repo.or.cz/pspdecompiler
9857781..52f17f2 master -> origin/master
Updating 9857781..52f17f2
constants.c: needs update
output.c: needs update
ssa.c: needs update
fatal: Entry 'constants.c' not uptodate. Cannot merge.
|
|
|
| Back to top |
|
 |
hlide
Joined: 10 Sep 2006 Posts: 750
|
Posted: Thu May 21, 2009 5:49 am Post subject: |
|
|
| hnaves wrote: | | I believe that the problem is fixed now. |
I think so as I cannot see the bugs I used to see any longer :) |
|
| Back to top |
|
 |
hlide
Joined: 10 Sep 2006 Posts: 750
|
Posted: Mon Jun 01, 2009 4:16 am Post subject: |
|
|
pspdecompiler has trouble with tail call.
int f(int a) { return g(a); }
f will call g through a J instead of JAL, and it seems f is not reckoned properly because of this.
J can be considered as a call if it has the same arguments and result registers and the callee is defined as a function. So this J can be handled as a return. |
|
| Back to top |
|
 |
KickinAezz
Joined: 03 Jun 2007 Posts: 328
|
Posted: Mon Jun 01, 2009 6:01 am Post subject: |
|
|
Awesome project.
Hopefully once PSP GO! is hacked, we can play with bluetooth protocols unrestrictedly. _________________ Intrigued by PSP system Since December 2006.
Use it more for Development than for Gaming. |
|
| Back to top |
|
 |
Wally

Joined: 26 Sep 2005 Posts: 672
|
Posted: Mon Jun 01, 2009 8:32 am Post subject: |
|
|
| KickinAezz wrote: | Awesome project.
Hopefully once PSP GO! is hacked, we can play with bluetooth protocols unrestrictedly. |
that is if anyone buys that damn ugly thing |
|
| Back to top |
|
 |
hnaves
Joined: 03 Feb 2009 Posts: 30
|
Posted: Tue Jun 09, 2009 12:29 pm Post subject: |
|
|
| hlide wrote: | pspdecompiler has trouble with tail call.
int f(int a) { return g(a); }
f will call g through a J instead of JAL, and it seems f is not reckoned properly because of this.
J can be considered as a call if it has the same arguments and result registers and the callee is defined as a function. So this J can be handled as a return. |
Did you manage to solve the problem? |
|
| Back to top |
|
 |
hlide
Joined: 10 Sep 2006 Posts: 750
|
Posted: Wed Jun 10, 2009 4:00 am Post subject: |
|
|
no, i didn't. I don't know all the details about pspdecompiler source enough to solve those problems.
I also noticed that constant return values are not always treated (I was forced to use prxtool to retrieve some return values).
Have you any plan to handle float as well ? their handling is quite similar to int but don't know if it is easily feasible. |
|
| Back to top |
|
 |
|