URL
https://opencores.org/ocsvn/or2k/or2k/trunk
Subversion Repositories or2k
Compare Revisions
- This comparison shows the changes necessary to convert path
/or2k/trunk
- from Rev 27 to Rev 28
- ↔ Reverse comparison
Rev 27 → Rev 28
/analysis-bin/insnanalysis/or1k-32-insn.c
778,14 → 778,20
break; |
} |
break; |
|
// The l.sx instructions'd rD is actually in the location rA is for |
// every other instruction - so we specify has_rA, but really that's |
// the rD, so it's l.sx imm(rA), rB |
case 0x34: |
insn_props->insn_string="l.sd"; |
insn_props->insn_index=81; |
insn_props->has_rA = 1; |
insn_props->has_rB = 1; |
break; |
|
case 0x35: |
insn_props->insn_string="l.sw"; |
insn_props->has_rA = 1; |
insn_props->has_rB = 1; |
insn_props->has_split_imm = 1; |
insn_props->insn_index=82; |
break; |
792,6 → 798,8
|
case 0x36: |
insn_props->insn_string="l.sb"; |
insn_props->has_rA = 1; |
insn_props->has_rB = 1; |
insn_props->has_split_imm = 1; |
insn_props->insn_index=83; |
break; |
798,6 → 806,8
|
case 0x37: |
insn_props->insn_string="l.sh"; |
insn_props->has_rA = 1; |
insn_props->has_rB = 1; |
insn_props->has_split_imm = 1; |
insn_props->insn_index=84; |
break; |
1001,12 → 1011,59
return 0; |
} |
|
// Function to track entire instructions, regardless of architecture |
// Storage list: |
// Format: [0] - binary copy of instruction |
// [1] - occurrence count |
uint32_t (*bin_insn_list)[2] = NULL; |
int bin_insn_list_count = -1; |
#define NUM_EXPECTED_UNIQUE_INSNS 50000 |
void record_bin_insn(uint32_t insn) |
{ |
// Check if the array has been initialised yet |
if (bin_insn_list_count == -1) |
{ |
bin_insn_list = calloc((NUM_EXPECTED_UNIQUE_INSNS*2)*sizeof(uint32_t),1); |
bin_insn_list_count = 0; |
} |
|
int list_check_itr; |
// Go through the list, check if we've seen this one before |
for(list_check_itr=0;list_check_itr<bin_insn_list_count;list_check_itr++) |
if (bin_insn_list[list_check_itr][0] == insn) |
{ |
// Seen it before, just increment count |
bin_insn_list[list_check_itr][1]++; |
return; |
} |
|
|
// If we're here, we've not seen this one before, it's new |
|
// No room left in list to add new ones |
if ( bin_insn_list_count == NUM_EXPECTED_UNIQUE_INSNS ) |
return; |
|
// Add it to the list |
bin_insn_list[bin_insn_list_count][0] = insn; |
bin_insn_list[bin_insn_list_count][1] = 1; |
|
bin_insn_list_count++; |
|
// No room left in list to add new ones |
if ( bin_insn_list_count == NUM_EXPECTED_UNIQUE_INSNS ) |
fprintf(stderr, "Warning: bin_insn_list[][] full (%d entries)\n", |
NUM_EXPECTED_UNIQUE_INSNS); |
|
|
} |
|
// Entry point for statistics collection. |
// Passed binary copy of instruction, and pointer to properties struct |
// Each function that can collect staistics is called. |
void or1k_32_collect_stats(uint32_t insn, |
struct or1k_32_instruction_properties * insn_props) |
struct or1k_32_instruction_properties * insn_props, |
int record_bin_insns) |
{ |
// Add this instruction's occurrence to our data |
insn_lists_add(insn, insn_props); |
1019,10 → 1076,12
for(n=2;n<OR1K_MAX_GROUPINGS_ANALYSIS+1;n++) |
insn_lists_group_add(n, insn_props); |
} |
|
|
if (record_bin_insns) |
record_bin_insn(insn); |
|
// Finished adding to stats for this instruction |
|
|
} |
|
// Function to add entry to, or increment incidences of, value in the value list |
1800,6 → 1859,139
} |
|
|
// Print out the top n seen entire instructions |
void print_top_bin_insn(FILE * stream, int n) |
{ |
int largest_indx = 0; |
int bin_insn_list_itr; |
|
// Copy the counts, so we can trash them as needed |
int bin_insn_counts[NUM_EXPECTED_UNIQUE_INSNS]; |
|
// An instruction properties object |
struct or1k_32_instruction_properties insn_props; |
|
for(bin_insn_list_itr=0;bin_insn_list_itr<bin_insn_list_count; |
bin_insn_list_itr++) |
bin_insn_counts[bin_insn_list_itr] = bin_insn_list[bin_insn_list_itr][1]; |
|
#ifdef DISPLAY_STRING |
fprintf(stream, "Top %d seen instructions\n", n); |
fprintf(stream, "Saw %d unique instructions\n", bin_insn_list_count); |
#endif |
#ifdef DISPLAY_CSV |
fprintf(stream, ",\n"); |
fprintf(stream,"\"Top %d instructions\",\n\"Total unique instructions\",%d\n", |
n, bin_insn_list_count); |
fprintf(stream, |
"\"Instruction (bin)\",\"Dissassembly\",\"Occurrences\",\"Freq\"\n"); |
#endif |
|
while (n--) |
{ |
// Search for the largest count |
for(bin_insn_list_itr=0;bin_insn_list_itr<bin_insn_list_count; |
bin_insn_list_itr++) |
largest_indx = (bin_insn_counts[bin_insn_list_itr] > |
bin_insn_counts[largest_indx]) ? |
bin_insn_list_itr : largest_indx; |
|
// Gone through list, largest_indx is the biggest index |
|
// Clear the instruction properties struct |
memset(&insn_props, 0, sizeof(struct or1k_32_instruction_properties)); |
|
// Get the string for this instruction |
or1k_32_analyse_insn(bin_insn_list[largest_indx][0], &insn_props); |
|
// Print out the instruction |
#ifdef DISPLAY_STRING |
fprintf(stream, "Insn:\t0x%.8x\t%s",bin_insn_list[largest_indx][0], |
insn_props.insn_string); |
#endif |
#ifdef DISPLAY_CSV |
fprintf(stream, "\"0x%.8x\",\"%s",bin_insn_list[largest_indx][0], |
insn_props.insn_string); |
#endif |
|
if (insn_props.has_jumptarg || insn_props.has_branchtarg) |
#ifdef DISPLAY_STRING |
fprintf(stream, " 0x%x", (bin_insn_list[largest_indx][0] & JUMPTARG_MASK) << 2 ); |
#endif |
#ifdef DISPLAY_CSV |
fprintf(stream, " 0x%x", (bin_insn_list[largest_indx][0] & JUMPTARG_MASK) << 2 ); |
#endif |
|
|
if (insn_props.has_rD) |
#ifdef DISPLAY_STRING |
fprintf(stream, " r%d", |
insn_or1k_32_rD(bin_insn_list[largest_indx][0])); |
#endif |
#ifdef DISPLAY_CSV |
fprintf(stream, " r%d", |
insn_or1k_32_rD(bin_insn_list[largest_indx][0])); |
#endif |
|
if (insn_props.has_rA) |
#ifdef DISPLAY_STRING |
fprintf(stream, " r%d", |
insn_or1k_32_rA(bin_insn_list[largest_indx][0])); |
#endif |
#ifdef DISPLAY_CSV |
fprintf(stream, " r%d", |
insn_or1k_32_rA(bin_insn_list[largest_indx][0])); |
#endif |
|
if (insn_props.has_rB) |
#ifdef DISPLAY_STRING |
fprintf(stream, " r%d", |
insn_or1k_32_rB(bin_insn_list[largest_indx][0])); |
#endif |
#ifdef DISPLAY_CSV |
fprintf(stream, " r%d", |
insn_or1k_32_rB(bin_insn_list[largest_indx][0])); |
#endif |
|
|
if (insn_props.has_imm) |
#ifdef DISPLAY_STRING |
fprintf(stream, " 0x%x", |
insn_or1k_32_imm(bin_insn_list[largest_indx][0])); |
#endif |
#ifdef DISPLAY_CSV |
fprintf(stream, " 0x%x", |
insn_or1k_32_imm(bin_insn_list[largest_indx][0])); |
#endif |
|
if (insn_props.has_split_imm) |
#ifdef DISPLAY_STRING |
fprintf(stream, " 0x%x", |
insn_or1k_32_split_imm(bin_insn_list[largest_indx][0])); |
#endif |
#ifdef DISPLAY_CSV |
fprintf(stream, " 0x%x", |
insn_or1k_32_split_imm(bin_insn_list[largest_indx][0])); |
#endif |
|
#ifdef DISPLAY_STRING |
fprintf(stream, "\tcount:\t%d (%f%%)\n",bin_insn_list[largest_indx][1], |
(float)((float)bin_insn_list[largest_indx][1])/ |
((float)num_seen_insns)); |
#endif |
#ifdef DISPLAY_CSV |
fprintf(stream, "\",%d,%f\n",bin_insn_list[largest_indx][1], |
(float)((float)bin_insn_list[largest_indx][1])/ |
((float)num_seen_insns)); |
#endif |
|
// Finished printing out its instruction |
bin_insn_counts[largest_indx] = -1; |
|
} |
} |
|
|
// Print out the stats relating to the sequences of instructions most |
// common before seeing this instruction |
void or1k_32_generate_groupings_stats(struct or1k_insn_info *insn_info, |
1866,12 → 2058,15
fprintf(stream, "Individual instruction frequency:\n"); |
#endif |
or1k_32_most_freq_insn(stream); |
|
// If we did the binary instruction frequency counting, print it out |
if (bin_insn_list_count != -1) |
print_top_bin_insn(stream, 20); |
|
} |
|
|
|
|
// Free up all added instruction statistic tracking structs |
void or1k_32_insn_lists_free(void) |
{ |
1882,4 → 2077,7
if (or1k_32_insns[insn_index] != NULL) |
free(or1k_32_insns[insn_index]); |
} |
|
if (bin_insn_list_count != -1) |
free(bin_insn_list); |
} |
/analysis-bin/insnanalysis/or1k-32-insn.h
113,7 → 113,8
|
// Stat collection entry-oint |
void or1k_32_collect_stats(uint32_t insn, |
struct or1k_32_instruction_properties * insn_props); |
struct or1k_32_instruction_properties * insn_props, |
int record_bin_insns); |
|
|
// List management/analysis functions |
/analysis-bin/insnanalysis/insnanalysis.c
5,10 → 5,12
|
*/ |
|
#include<stdio.h> |
#include <ctype.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
#include <stdint.h> |
#include <unistd.h> |
#include <arpa/inet.h> // for htonl() |
|
#include "insnanalysis.h" |
31,9 → 33,9
} |
|
void collect_stats(instruction insn, |
instruction_properties *insn_props) |
instruction_properties *insn_props, int record_unique) |
{ |
or1k_32_collect_stats(insn, insn_props); |
or1k_32_collect_stats(insn, insn_props, record_unique); |
} |
|
|
44,37 → 46,73
|
int main(int argc, char *argv[]) |
{ |
FILE *fp; |
FILE *ifp, *ofp; |
|
char insn_buff[INSN_SIZE_BYTES]; // Buffer for instruction data |
|
int insns_seen_total = 0; // Keep track of total number of instructions read |
|
// Try to open the file passed as first parameter |
if((fp = fopen(argv[ 1 ], "rb"))==NULL) { |
printf("Cannot open file.\n"); |
char *infilename = NULL; |
char *outfilename = NULL; |
|
int outfile_flag = 0; // default is not to use an output file |
|
int opterr = 0; |
|
int uniquecount_flag = 0; |
|
int c; |
|
// Look for: |
// -f filename : Input file name (required) |
// [ -o filename] : Output file name (optional) |
// [ -u ] : Do unique instruction analysis (option) |
while ((c = getopt(argc, argv, "f:o:u::")) != -1) |
switch (c) |
{ |
case 'f': |
infilename = optarg; |
break; |
|
case 'o': |
outfile_flag = 1; |
outfilename = optarg; |
break; |
|
case 'u': |
uniquecount_flag = 1; |
break; |
|
default: |
abort(); |
} |
|
|
// Try to open the input file |
if((ifp = fopen(infilename, "rb"))==NULL) { |
printf("Cannot open input file, %s\n", infilename); |
exit(1); |
} |
|
|
int filesize_bytes, filesize_insns; |
// Determine filesize |
if ( fseek(fp, 0, SEEK_END)) |
if ( fseek(ifp, 0, SEEK_END)) |
{ |
fclose(fp); |
fprintf(stderr, "Error detecting filesize\n"); |
fclose(ifp); |
fprintf(stderr, "Error detecting input file size\n"); |
return -1; |
} |
|
filesize_bytes = ftell(fp); |
filesize_bytes = ftell(ifp); |
filesize_insns = filesize_bytes / INSN_SIZE_BYTES; |
|
#ifdef DISPLAY_STRING |
printf("\nAnalysing file:\t%s\tSize: %d MB\n", |
argv[1],((filesize_bytes/1024)/1024)); |
infilename,((filesize_bytes/1024)/1024)); |
#endif |
|
// Reset pointer |
rewind(fp); |
rewind(ifp); |
|
instruction * insn = (instruction *)insn_buff; |
|
88,9 → 126,9
|
insn_lists_init(); |
|
while(!feof(fp)) { |
while(!feof(ifp)) { |
|
if (fread(insn_buff, INSN_SIZE_BYTES, 1, fp) != 1) |
if (fread(insn_buff, INSN_SIZE_BYTES, 1, ifp) != 1) |
break; |
|
// Endianness is little when read in from binary file created with |
107,7 → 145,8
|
insns_seen_total++; |
|
collect_stats(*insn, &insn_props); |
collect_stats(*insn, &insn_props, uniquecount_flag); |
|
} |
else |
{ |
128,17 → 167,32
} |
} |
|
fclose(fp); |
fclose(ifp); |
|
fprintf(stderr, "\rDone\n", percent); |
|
// Try to open the output file |
if (outfile_flag) |
{ |
if((ofp = fopen(outfilename, "wb+"))==NULL) { |
printf("Cannot open output file.\n"); |
exit(1); |
} |
} |
else |
// Otherwise we'll use stdout |
ofp = (FILE *)stdout; |
|
#ifdef DISPLAY_STRING |
fprintf(stdout, "Saw %d instructions\n", insns_seen_total); |
fprintf(ofp, "Saw %d instructions\n", insns_seen_total); |
#endif |
#ifdef DISPLAY_CSV |
fprintf(stdout, "\"File:\",\"%s\",\"Num insns:\",%d,\n", |
argv[1], insns_seen_total); |
fprintf(ofp, "\"File:\",\"%s\",\"Num insns:\",%d,\n", |
infilename, insns_seen_total); |
#endif |
generate_stats(stdout); |
|
// Generate output |
generate_stats(ofp); |
|
insn_lists_free(); |
|
/analysis-bin/insnanalysis/Makefile
14,7 → 14,8
|
|
test: test.bin $(APP) |
./$(APP) $< |
./$(APP) -f $< |
./$(APP) -f $< -o /dev/null |
|
test.bin: test.o |
or32-elf-objcopy -O binary $< $@ |
/analysis-bin/insnanalysis/README
26,20 → 26,17
|
$ make test |
|
To run the program itself, just give it a binary blob of instructions (usually |
the output of objcopy -O binary). |
|
Static analysis: |
|
For instance the Linux kernel ELF for OR1K can be prepared with the following |
command: |
To generate a raw binary representation of the instructions that end up in |
something like the Linux kernel, take the ELF file that results from compilation |
and pass it to or32-elf-objcopy like the following: |
|
$ or32-elf-objcopy -O binary -j .text -S vmlinux vmlinux.text.bin |
|
It is passed to the program like so, and the output is captured by redirecting |
stdout. |
Use the -f flag to indicate the input file, and -o to indicate the output file. |
|
$ ./insnanalysis vmlinux.text.bin > vmlinux.insnanalysis |
$ ./insnanalysis -f vmlinux.text.bin o vmlinux.insnanalysis |
|
Dynamic analysis with binary execution log from or1ksim: |
|
60,11 → 57,20
"#define DISPLAY_" defines in the instruction set header. The program must be |
recompiled if this is changed. |
|
Individual instruction analysis: |
|
Instead of only breaking the instruction up and recording statistics on an |
opcode basis - the instructions can be tracked in their entireity and statistics |
on the most frequently seen entire instruction presented. Use the -u flag when |
running the program. Note that this will make execution time longer. For a |
binary trace of Linux booting 1.7GB in size, a 2.5GHz Intel Core 2 Duo machine |
took 30 minutes to parse with the -u option. |
|
|
TODO: |
o Collect and display information about l.j and l.jal instruction immediates |
o Add an easy way to switch between human readable and CSV output |
o Figure out how to tack this thing onto a simulator (or1ksim maybe) to give |
o Figure out how to tack this thing onto a simulator (or1ksim for now) to give |
results of execution when that finishes executing, or just how to get the |
simulator to output a binary dump of executed instructions to be fed through |
this |
74,4 → 80,4
the instruction sequence data would then be accurate for static analysis. |
|
|
July 24, 2010 - Julius Baxter |
July 25, 2010 - Julius Baxter |