OpenCores
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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.