I am currently attempting to output assembly using the script below:
for instr in currentProgram.getListing().getInstructions(True):
print("\" " + str(instr) + "\\n\\t" + "\"")
It produces output like below:
" ADD RBX,0x1\n\t"
" CMP RBP,RBX\n\t"
" JNZ 0x001012b0\n\t"
" ADD RSP,0x8\n\t"
This works great for every instruction except anything that modifies the execution flow, such as jumps or calls. I'd ideally like the output to be:
" ADD RBX,0x1\n\t"
" CMP RBP,RBX\n\t"
" JNZ -0x10\n\t"
" ADD RSP,0x8\n\t"
Because in this example, the JNZ instruction jumps to an address a distance of 0x10 before this instruction. I can see this in the instruction bytes of 75 ea (75 being a jnz, and ea being -0x10), but I don't know how to get this value from the ghidra scripting api. Can you help me get this value for the output I'm expecting?
Related
Is it possible to Execute TI BASIC from a string? Such that:
execute(":Disp Str1")
would Print out Str1?
It could be done with a small Asm( program that takes a string (from Ans), turns it into a BASIC program, and executes it. For example:
.nolist
#include "ti83plus.inc"
.list
.org userMem-2
.db $BB,$6D
ld hl,SavesScreen
ld (hl),tTheta
inc hl
ld (hl),0
inc hl
push hl
bcall(_AnsName)
rst rFindSym
ex de,hl
ld c,(hl)
inc hl
ld b,(hl)
dec hl
inc bc
inc bc
pop de
ldir
ld hl,SavesScreen
ld a,6
bcall(_ExecuteNewPrgm)
; no ret because _ExecuteNewPrgm does not return
This is not ideal,
No safety in case Ans did not contain a string (could be added).
A program named θ should not exist, because it will be overwritten. If prgmθ already exists and is archived, then it does not work at all. (could be improved)
prgmθ is not deleted afterwards. (not sure how to do this)
When prgmθ is done, it quits to the Homescreen, it does not return to the calling program. (not sure how to do this)
Aside from that, it does work, for example:
:"TESTING->Str1
:":Disp Str1
:Asm(prgmRUNSTR
Looks like this afterwards:
You can create the assembly program by typing this into a normal program:
AsmPrgmBB6D21
EC86365B2336
0023E5EF524B
D7EB4E23462B
0303D1EDB021
EC863E06EF3C
4C
It can be made smaller with AsmComp(.
Unfortunately, no, not like this- expr and eval only work on expressions.
My code below is supposed to simply print a prompt, but it's printing a bunch of y-looking characters instead. Any idea of what I'm doing wrong?
CODE:
startPrompt .STRINGZ "Enter 'E' to encrpyt, 'D' to decrpyt, X to quit\n"
startPromptAddress .FILL startPrompt
LDI R0, startPromptAddress
PUTS
I think you want LEA, not LDI.
LEA Loads a register with the ADDRESS of LABEL (not its contents!). Often used with .STRINGZ and PUTS to print a string.
LDI gets the address that is stored at the LABEL (or an offset), and then gets the VALUE at THAT address (this is the indirect "i" part of LDI).
Here's the full code that should work in a typical LC3 simulator (I used the one at lc3tutor.org to verify:
--------------- cut here ---------------
.ORIG x3000
startPrompt .STRINGZ "Enter 'E' to encrpyt, 'D' to decrpyt, X to quit\n"
LEA R0, startPrompt; load the address at 'startPrompt' into R0
PUTS; print characters starting at R0 and continuing until the null character is reached (automatically part of the memory initialized when you use the .STRINGZ directive).
.END
-------------- cut here ---------------
Hope this helps
Jeff
I rarely do scripting and I have problem using reg expression using Jmeter's beanshell.
Basically, I have an output of 16 digits. I wanted to search the string, separate every 2nd character, and prepend with '0x' followed by a space, repeat for all 16 digits, lastly using vars.put into a self defined parameters. I have managed to do this in bash easily but not able to find solution with Beanshell Jmeter.
// get current date
var d = new Date();
// convert to epoch
var militime = d.getTime();
// convert to 16digit
//var nowtime1 = (long.valueOf(militime) * 1000);
var nowtime1 = militime * 1000;
var nowtime1 = nowtime1.replace(/({0,2})/g,"x0"); //I'm unsure of the syntax here
Does anyone has suggestion to improve?
This is sample output from my bash script using sed to format:
1495207922508835
0x14 0x95 0x20 0x79 0x22 0x50 0x88 0x35
Using Beanshell is some form of antipattern when it comes to creating JMeter scripts, you should consider using JSR223 Test Elements and Groovy language instead as Groovy is less resource intensive, has much better performance and it is more Java-compliant.
Coming back to your question, Groovy implementation of your requirement would be something like:
def now = "1495207922508835"
def result = new StringBuilder()
now.split("(?<=\\G..)").each {
result.append("0x").append(it).append(" ")
}
log.info(result.toString())
Demo:
See Groovy is the New Black guide to learn about why and how you should be using Groovy in JMeter tests.
NB: adding 0x doesn't really convert an integer into hex, you might want to consider Integer.toHexString() method instead.
I would simplify current time retrieval to System.currentTimeMillis() * 1000. Second, you are trying to manipulate number as if it's a string, but then you need to convert it to string. Regex itself is almost right. So the whole script looks like this:
now = "" + (java.lang.System.currentTimeMillis() * 1000);
result = now.replaceAll("(.{2})", "0x$1 ");
Example:
now result
1495215390956000 0x14 0x95 0x21 0x53 0x90 0x95 0x60 0x00
1495215441281000 0x14 0x95 0x21 0x54 0x41 0x28 0x10 0x00
My goal is to write a string to a file where the size of the string will vary. At the moment I have made the string very large so that there is no overflow but is there a way to make it so that the size of the string is the exact number of characters I'm placing into it? I've tried something like the code below but it gives me an error unknown identifier "address count" I think it is because address count is a variable declared in a process and address count is constantly changing. Is there any way around this?
signal address_map :string (1 to address_count);
many thanks
leo
"My goal is to write a string to a file." Hence, lets just focus on that.
Step 1: reference the file IO packages (recommended to turn on VHDL-2008):
use std.textio.all ;
-- use ieee.std_logic_textio.all ; -- include if not using VHDL-2008
Step 2: Declare your file
file MyFile : TEXT open WRITE_MODE is "MyFile.txt";
Step 3: Create a buffer:
TestProc : process
variable WriteBuf : line ;
begin
write ... -- see step 4
writeline ... -- see step 5
Step 4: Use write to write into the buffer (in the process TestProc):
write(WriteBuf, string'("State = ") ) ; -- Any VHDL version
write(WriteBuf, StateType'image(State)) ;
swrite(WriteBuf, " at time = " ); -- VHDL-2008 simplification
write(WriteBuf, NOW, RIGHT, 12) ;
Step 5: Write the buffer to the file (in the process TestProc):
writeline(MyFile, WriteBuf) ;
Alternate Steps 3-5: Use built-in VHDL Write with to_string:
Write(MyFile, "State = " & to_string(State) &
", Data = " & to_hstring(Data) &
" at time " & to_string(NOW, 1 ns) ) ;
Alternate Steps 1-5: Use OSVVM (see http://osvvm.org) (requires VHDL-2008):
library osvvm ;
use osvvm.transcriptpkg.all ; -- all printing goes to same file
. . .
TestProc : process
begin
TranscriptOpen("./results/test1.txt") ;
Print("State = " & to_string(State) &
", Data = " & to_hstring(Data) &
" at time " & to_string(NOW, 1 ns) ) ;
One hard but flexible solution is to use dynamic allocation features of VHDL (copied from ADA).
You have to use an access of string (it is roughly like a "pointer to a string" in C)
type line is access string;
you event don't have to do it because line is already declared in std.textio package.
Ok, the problem next is that you can't use an access type for a signal, so you have to use a shared variable:
shared variable address_map: line;
And finally you have to allocate, read and write to this line:
--Example in a function/procedure/process:
--free a previously allocated string:
if address_map /= NULL then
deallocate(address_map);
end if;
--allocate a new string:
address_map:=new string (1 to address_count);
address_map(1 to 3):="xyz";
--we have here:
-- address_map(1)='y'
-- address_map(2 to 3)="yz"
-- address_map.all = "xyz"
Notice the use of new/deallocate (like malloc/free in C or free/delete in C++).
It is not easy to handle this kind of code, I recommend you to read the documentation of VHDL keywords "new", "deallocate" and "access" (easily found with your favorite search engine) or feel free to ask more questions.
You can also use the READ (read the whole line into a string) and WRITE (append a string to the line) functions from std.textio package.
Program Description
I used .BLKW to allocate 20 locations for each character that the user inputs and for now, I just want to display the string the user typed at the first prompt. (This will be a pig latin translator, hence the second prompt; but right now I just want to see if I can print out the user input)
The Problem
The problem is that when I run it, I get extra characters at the end.
For example:
English Word: apple
Pig-Latin Word: apple
English Word: at
Pig-Latin Word: atple
English Word: set
Pig-Latin Word: setle
My Program
.ORIG x3000
START ST R1,SAVER1
ST R2,SAVER2
ST R3,SAVER3
LD R5,ENTER
REPEAT LEA R0,PROMPT ; loading the starting address of prompt
PUTS ; displays PROMPT on screen
LEA R4,ENGLWORD ; sets aside memory locations for typed characters
INPUT GETC ; now that user has typed, read char into R0
ADD R6,R5,R0 ; adds the negative value of the ASCII enter key code to the input character
BRz PIGPROMPT ; if the sum of the ASCII codes from step before is 0, that means user pressed enter so go to PIGPROMPT
OUT ; write char in R0 to console
STR R0,R4,#0 ; store typed character into memory location
ADD R4,R4,#1 ; increment memory location so you write next character to the next location
BRnzp INPUT ; break no matter what to the INPUT step to receive next typed character
PIGPROMPT LEA R0,PIG ; loads starting address of pig latin prompt
PUTS ; displays pig latin prompt on screen
LEA R0,ENGLWORD
PUTS
BRnzp REPEAT
LD R1,SAVER1 ; restore R1 to original value
LD R2,SAVER2 ; restore R2 to original value
LD R3,SAVER3 ; restore R3 to original value
HALT
SAVER1 .BLKW 1 ; allocates 1 memory location for SAVER1
SAVER2 .BLKW 1 ; allocates 1 memory location for SAVER2
SAVER3 .BLKW 1 ; allocates 1 memory location for SAVER3
ENGLWORD .BLKW #20
ENTER .FILL xFFF6 ; the negative value of the ASCII code for the enter key
NEWLINE .FILL x000A
PROMPT .STRINGZ "\nEnglish Word: " ; initializes a sequence of stringLength+1 memory locations to hold string
PIG .STRINGZ "\nPig-Latin Word: "
DSR .FILL xFE04
DDR .FILL xFE06
KBSR .FILL xFE00
KBDR .FILL xFE02
.END
Attempted Solution
I was thinking that the problem was that R4 holds the string of the first user input throughout the whole program. So for a solution, I thought about clearing R4 after it is displayed so that it's ready to take the next user input. Does anyone know how I would do that?
The key here is how PUTS works -- it prints all the characters starting at the address in R0 until it reaches a 0 ('\0' not '0').
The first time you run it, the memory will contain ['A','P','P','L','E'], followed by zeroes if you didn't randomize memory contents when you loaded the program. This means that a PUTS call will return "APPLE". When you enter the new word, it doesn't clear out that memory, so entering "at" will result in ['A','T','P','L','E'], and your print routine will print "ATPLE".
In order to properly finish the word, you need to add a '\0' (a.k.a. 0) to the element after the last character to print. In other words, if your memory contains ['A','T','\0','L','E'], your print routine will print "AT".
Aqua's right, the PUTs command is looking for a zero to stop printing characters to the screen. I've added two lines of code just after PIGPROMPT and it seems to be working as intended.
Revised:
.ORIG x3000
START ST R1,SAVER1
ST R2,SAVER2
ST R3,SAVER3
LD R5,ENTER
REPEAT LEA R0,PROMPT ; loading the starting address of prompt
PUTS ; displays PROMPT on screen
LEA R4,ENGLWORD ; sets aside memory locations for typed characters
INPUT GETC ; now that user has typed, read char into R0
ADD R6,R5,R0 ; adds the negative value of the ASCII enter keycode to the input character
BRz PIGPROMPT ; if the sum of the ASCII codes from step before is 0, that means user pressed enter so go to PIGPROMPT
OUT ; write char in R0 to console
STR R0,R4,#0 ; store typed character into memory location
ADD R4,R4,#1 ; increment memory location so you write next character to the next location
BRnzp INPUT ; break no matter what to the INPUT step to receive next typed character
PIGPROMPT AND R0, R0, #0 ; clear R0
STR R0,R4,#0 ; store typed character into memory location
LEA R0,PIG ; loads starting address of pig latin prompt
PUTS ; displays pig latin prompt on screen
LEA R0,ENGLWORD
PUTS
BRnzp REPEAT
LD R1,SAVER1 ; restore R1 to original value
LD R2,SAVER2 ; restore R2 to original value
LD R3,SAVER3 ; restore R3 to original value
HALT
SAVER1 .BLKW 1 ; allocates 1 memory location for SAVER1
SAVER2 .BLKW 1 ; allocates 1 memory location for SAVER2
SAVER3 .BLKW 1 ; allocates 1 memory location for SAVER3
ENGLWORD .BLKW #20
ENTER .FILL xFFF6 ; the negative value of the ASCII code for the enter key
NEWLINE .FILL x000A
PROMPT .STRINGZ "\nEnglish Word: " ; initializes a sequence of stringLength+1 memory locations to hold string
PIG .STRINGZ "\nPig-Latin Word: "
DSR .FILL xFE04
DDR .FILL xFE06
KBSR .FILL xFE00
KBDR .FILL xFE02
.END
All I did was store a '0' value at the end of the user's string, that way when PUTs is called it will stop at the zero value.