Initial commit

This commit is contained in:
2025-10-06 00:14:04 -04:00
commit d98bdabb74
553 changed files with 32764 additions and 0 deletions

51
p1-check/Makefile Normal file
View File

@@ -0,0 +1,51 @@
#
# Simple Makefile
# Mike Lam, James Madison University, August 2016
#
# This makefile builds a simple application that contains a main module
# (specified by the EXE variable) and a predefined list of additional modules
# (specified by the MODS variable). If there are any external library
# dependencies (e.g., the math library, "-lm"), list them in the LIBS variable.
# If there are any precompiled object files, list them in the OBJS variable.
#
# By default, this makefile will build the project with debugging symbols and
# without optimization. To change this, edit or remove the "-g" and "-O0"
# options in CFLAGS and LDFLAGS accordingly.
#
# By default, this makefile build the application using the GNU C compiler,
# adhering to the C99 standard with all warnings enabled.
# application-specific settings and run target
EXE=y86
MODS=p1-check.o
OBJS=
LIBS=
default: $(EXE)
test: $(EXE)
TPREFIX=tests/ make -C tests test
# compiler/linker settings
CC=gcc
CFLAGS=-g -O0 -Wall --std=c99 -pedantic
LDFLAGS=-g -O0
# build targets
$(EXE): main.o $(MODS) $(OBJS)
$(CC) $(LDFLAGS) -o $(EXE) $^ $(LIBS)
%.o: %.c
$(CC) -c $(CFLAGS) $<
clean:
rm -f $(EXE) main.o $(MODS)
make -C tests clean
.PHONY: default clean

57
p1-check/elf.h Normal file
View File

@@ -0,0 +1,57 @@
#ifndef __CS261_ELF__
#define __CS261_ELF__
#include <stdio.h>
#include <stdint.h>
/*
Mini-ELF file format (byte 0 = first byte of the file)
+----------------------------------------------+
| header (elf_hdr_t) - 16 bytes |
+----------------------------------------------+
| program headers (elf_phdr_t) - 20 bytes each |
+----------------------------------------------+
| program segments - variable length of bytes |
+----------------------------------------------+
| symbol table - each entry is 4 bytes each |
+----------------------------------------------+
| string table - variable length of strings |
+----------------------------------------------+
ELF header structure:
+----------------------------------------------------------------------------+
| 0 1 | 2 3 | 4 5 | 6 7 | 8 9 | 10 11 | 12 13 14 15 |
| version | entry | phdr | numphdr | symtab | strtab | magic number |
+----------------------------------------------------------------------------+
Sample ELF header (all entries in hex, format is little endian):
+----------------------------------------------------------------------------+
| 01 00 | 00 01 | 10 00 | 02 00 | 58 00 | 70 00 | 45 4c 46 00 |
| version | entry | phdr | numphdr | symtab | strtab | magic number |
+----------------------------------------------------------------------------+
version = 0x0001 entry = 0x0100 phdr = 0x0010 numphdr = 0x0002
symtab = 0x0058 strtab = 0x0070 magic = "ELF\0"
Interpretation:
This file was created under version 1 of this format. When the program is
loaded into memory, the instruct at address 0x100 (256) will be executed
first. The first program header (which indicates segments in this file)
starts at offset 0x10 (16) into the file, and there are 2 program headers
total. The symbol table starts at offset 0x58 (88) into this file, and the
string table starts at offset 0x70 (112). The magic number is the string
"ELF\0", stored in the elf_hdr_t format as a 4-byte integer 0x00464c45
(4607045) and is used for checking the validity of the header.
*/
typedef struct __attribute__((__packed__)) elf {
uint16_t e_version; /* version should be 1 */
uint16_t e_entry; /* entry point of program */
uint16_t e_phdr_start; /* start of program headers */
uint16_t e_num_phdr; /* number of program headers */
uint16_t e_symtab; /* start of symbol table */
uint16_t e_strtab; /* start of string table */
uint32_t magic; /* ELF */
} elf_hdr_t;
#endif

66
p1-check/main.c Normal file
View File

@@ -0,0 +1,66 @@
/*
* CS 261: Main driver
*
* Name: Nicholas Tamassia
*/
#include "p1-check.h"
/*
* helper function for printing help text
*/
void usage (char **argv)
{
printf("Usage: %s <option(s)> mini-elf-file\n", argv[0]);
printf(" Options are:\n");
printf(" -h Display usage\n");
printf(" -H Show the Mini-ELF header\n");
}
int main (int argc, char **argv)
{
int c;
bool display_header = false;
while ((c = getopt(argc, argv, "hH")) != -1) {
switch (c) {
case 'h':
usage(argv);
return EXIT_SUCCESS;
case 'H':
display_header = true;
break;
default:
usage(argv);
return EXIT_FAILURE;
}
}
/* Check if file path was the last argument */
if (optind != argc - 1) {
usage(argv);
return EXIT_FAILURE;
}
elf_hdr_t header = { 0 };
FILE *header_file = fopen(argv[optind], "r");
/* Invalid file path or failed to read correct data from file */
if (!read_header(header_file, &header)) {
printf("Failed to read file\n");
if (header_file != NULL) {
fclose(header_file);
}
return EXIT_FAILURE;
}
if (display_header) {
dump_header(&header);
}
fclose(header_file);
return EXIT_SUCCESS;
}

BIN
p1-check/main.o Normal file

Binary file not shown.

60
p1-check/p1-check.c Normal file
View File

@@ -0,0 +1,60 @@
/*
* CS 261 PA1: Mini-ELF header verifier
*
* Name: Nicholas Tamassia
*/
#include "p1-check.h"
/**********************************************************************
* REQUIRED FUNCTIONS
*********************************************************************/
bool read_header (FILE *file, elf_hdr_t *hdr)
{
if (!file || !hdr) {
return false;
}
return ((fread(hdr, sizeof(elf_hdr_t), 1, file) == 1) && hdr->magic == 0x00464c45);
}
/**********************************************************************
* OPTIONAL FUNCTIONS
*********************************************************************/
void dump_header (elf_hdr_t *hdr)
{
uint8_t *byte_arr = (uint8_t*)hdr;
size_t size = sizeof(elf_hdr_t) / sizeof(byte_arr[0]);
for (int i = 0; i < size; i++) {
printf("%02x", byte_arr[i]);
if (i != size - 1) {
printf(" ");
}
if (i == size / 2 - 1) {
printf(" ");
}
}
printf("\n");
printf("Mini-ELF version %d\n", hdr->e_version);
printf("Entry point 0x%03x\n", hdr->e_entry);
printf("There are %d program headers, starting at offset %d (0x%02x)\n", hdr->e_num_phdr, hdr->e_phdr_start, hdr->e_phdr_start);
if (hdr->e_symtab != 0) {
printf("There is a symbol table starting at offset %d (0x%02x)\n", hdr->e_symtab, hdr->e_symtab);
} else {
printf("There is no symbol table present\n");
}
if (hdr->e_strtab != 0) {
printf("There is a string table starting at offset %d (0x%02x)\n", hdr->e_strtab, hdr->e_strtab);
} else {
printf("There is no string table present\n");
}
}

29
p1-check/p1-check.h Normal file
View File

@@ -0,0 +1,29 @@
#ifndef __CS261_P1__
#define __CS261_P1__
#include <getopt.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "elf.h"
/**
* @brief Load a Mini-ELF header from an open file stream
*
* @param file File stream to use for input
* @param hdr Pointer to region where the Mini-ELF header should be loaded
* @returns True if the header was successfully loaded and verified, false otherwise
*/
bool read_header (FILE *file, elf_hdr_t *hdr);
/**
* @brief Print Mini-ELF header information to standard out
*
* @param hdr Header with info to print
*/
void dump_header (elf_hdr_t *hdr);
#endif

BIN
p1-check/p1-check.o Normal file

Binary file not shown.

81
p1-check/tests/Makefile Normal file
View File

@@ -0,0 +1,81 @@
#
# Simple Test Makefile
# Mike Lam, James Madison University, August 2016
#
# This version of the Makefile includes support for building a test suite. The
# recommended framework is Check (http://check.sourceforge.net/). To build and
# run the test suite, execute the "test" target. The test suite must be located
# in a module called "testsuite". The MODS, LIBS, and OBJS variables work as
# they do in the main Makefile.
#
# To change the default build target (which executes when you just type
# "make"), change the right-hand side of the definition of the "default"
# target.
#
# By default, this makefile will build the project with debugging symbols and
# without optimization. To change this, edit or remove the "-g" and "-O0"
# options in CFLAGS and LDFLAGS accordingly.
#
# By default, this makefile build the application using the GNU C compiler,
# adhering to the C99 standard with all warnings enabled.
# application-specific settings and run target
EXE=../y86
TEST=testsuite
MODS=public.o
OBJS=../p1-check.o private.o
LIBS=
UTESTOUT=utests.txt
ITESTOUT=itests.txt
default: $(TEST)
$(EXE):
make -C ../
test: utest itest
@echo "========================================"
utest: $(EXE) $(TEST)
@echo "========================================"
@echo " UNIT TESTS"
@./$(TEST) 2>/dev/null >$(UTESTOUT)
@cat $(UTESTOUT) | sed -n -e '/Checks/,$$p' | sed -e 's/^private.*:[EF]://g'
itest: $(EXE)
@echo "========================================"
@echo " INTEGRATION TESTS"
@./integration.sh | tee $(ITESTOUT)
# compiler/linker settings
CC=gcc
CFLAGS=-g -O0 -Wall --std=c99 -pedantic
LDFLAGS=-g -O0
CFLAGS+=-I/opt/homebrew/include -Wno-gnu-zero-variadic-macro-arguments
LDFLAGS+=-L/opt/homebrew/lib
LIBS+=-lcheck -lm -lpthread
ifeq ($(shell uname -s),Linux)
LIBS+=-lrt -lsubunit
endif
# build targets
$(TEST): $(TEST).o $(MODS) $(OBJS)
$(CC) $(LDFLAGS) -o $(TEST) $^ $(LIBS)
%.o: %.c
$(CC) -c $(CFLAGS) $<
clean:
rm -rf $(TEST) $(TEST).o $(MODS) $(UTESTOUT) $(ITESTOUT) outputs valgrind
.PHONY: default clean test unittest inttest

View File

@@ -0,0 +1 @@
Failed to read file

View File

@@ -0,0 +1 @@
Failed to read file

View File

@@ -0,0 +1,4 @@
Usage: ../y86 <option(s)> mini-elf-file
Options are:
-h Display usage
-H Show the Mini-ELF header

View File

@@ -0,0 +1,4 @@
Usage: ../y86 <option(s)> mini-elf-file
Options are:
-h Display usage
-H Show the Mini-ELF header

View File

@@ -0,0 +1,4 @@
Usage: ../y86 <option(s)> mini-elf-file
Options are:
-h Display usage
-H Show the Mini-ELF header

View File

@@ -0,0 +1,4 @@
Usage: ../y86 <option(s)> mini-elf-file
Options are:
-h Display usage
-H Show the Mini-ELF header

View File

@@ -0,0 +1 @@
Failed to read file

View File

@@ -0,0 +1 @@
Failed to read file

View File

@@ -0,0 +1 @@
Failed to read file

View File

@@ -0,0 +1,4 @@
Usage: ../y86 <option(s)> mini-elf-file
Options are:
-h Display usage
-H Show the Mini-ELF header

View File

@@ -0,0 +1,6 @@
01 00 00 01 10 00 04 00 00 00 00 00 45 4c 46 00
Mini-ELF version 1
Entry point 0x100
There are 4 program headers, starting at offset 16 (0x10)
There is no symbol table present
There is no string table present

View File

@@ -0,0 +1,6 @@
01 00 00 01 10 00 02 00 58 00 70 00 45 4c 46 00
Mini-ELF version 1
Entry point 0x100
There are 2 program headers, starting at offset 16 (0x10)
There is a symbol table starting at offset 88 (0x58)
There is a string table starting at offset 112 (0x70)

View File

@@ -0,0 +1,6 @@
01 00 00 01 10 00 05 00 f4 00 16 01 45 4c 46 00
Mini-ELF version 1
Entry point 0x100
There are 5 program headers, starting at offset 16 (0x10)
There is a symbol table starting at offset 244 (0xf4)
There is a string table starting at offset 278 (0x116)

View File

@@ -0,0 +1,6 @@
01 00 00 01 10 00 02 00 00 00 00 00 45 4c 46 00
Mini-ELF version 1
Entry point 0x100
There are 2 program headers, starting at offset 16 (0x10)
There is no symbol table present
There is no string table present

View File

View File

@@ -0,0 +1,6 @@
01 00 00 01 10 00 02 00 58 00 70 00 45 4c 46 00
Mini-ELF version 1
Entry point 0x100
There are 2 program headers, starting at offset 16 (0x10)
There is a symbol table starting at offset 88 (0x58)
There is a string table starting at offset 112 (0x70)

View File

@@ -0,0 +1 @@
01 00 00 01 10 00 02 00 58 00 70 00 45 4c 46 00

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,87 @@
#!/bin/bash
# extract executable name from Makefile
EXE=$(grep "EXE=" Makefile | sed -e "s/EXE=//")
# detect timeout utility (i.e., "timeout" on Linux and "gtimeout" on MacOS)
# and set timeout interval
TIMEOUT="timeout"
TIMEOUT_INTERVAL="3s"
$TIMEOUT --help &>/dev/null
if [[ $? -ne 0 ]]; then
TIMEOUT="gtimeout"
fi
# Valgrind additional output flags
VG_FLAGS="--leak-check=full --track-origins=yes"
function run_test {
# parameters
TAG=$1
ARGS=$2
PTAG=$(printf '%-30s' "$TAG")
# file paths
OUTPUT=outputs/$TAG.txt
DIFF=outputs/$TAG.diff
EXPECT=expected/$TAG.txt
VALGRND=valgrind/$TAG.txt
# run test with timeout
$TIMEOUT $TIMEOUT_INTERVAL $EXE $ARGS 2>/dev/null >"$OUTPUT"
if [ "$?" -lt 124 ]; then
# no timeout; compare output to the expected version
diff -u "$OUTPUT" "$EXPECT" >"$DIFF"
if [ -s "$DIFF" ]; then
# try alternative solution (if it exists)
EXPECT=expected/$TAG-2.txt
if [ -e "$EXPECT" ]; then
diff -u "$OUTPUT" "$EXPECT" >"$DIFF"
if [ -s "$DIFF" ]; then
echo "$PTAG FAIL (see ${TPREFIX}$DIFF for details)"
else
echo "$PTAG pass"
fi
else
echo "$PTAG FAIL (see ${TPREFIX}$DIFF for details)"
fi
else
echo "$PTAG pass"
fi
# run valgrind
$TIMEOUT $TIMEOUT_INTERVAL valgrind $VG_FLAGS $EXE $ARGS &>$VALGRND
else
echo "$PTAG FAIL (crash or timeout)"
fi
}
# initialize output folders
mkdir -p outputs
mkdir -p valgrind
rm -f outputs/* valgrind/*
# run individual tests
source itests.include
# check for memory leaks
LEAK=`cat valgrind/*.txt | grep 'definitely lost' | grep -v ' 0 bytes in 0 blocks'`
if [ -z "$LEAK" ]; then
echo "No memory leak found."
else
echo "Memory leak(s) found. See files listed below for details."
grep 'definitely lost' valgrind/*.txt | sed -e 's/:.*$//g' | awk "{print \" - ${TPREFIX}\" \$0}"
fi
# check for uninitialized values
LEAK=`cat valgrind/*.txt | grep 'uninitialised value'`
if [ -z "$LEAK" ]; then
echo "No uninitialized value found."
else
echo "Uninitialized value(s) found. See files listed below for details."
grep 'uninitialised value' valgrind/*.txt | sed -e 's/:.*$//g' | awk "{print \" - ${TPREFIX}\" \$0}"
fi

View File

@@ -0,0 +1,21 @@
# list of integration tests
# format: run_test <TAG> <ARGS>
# <TAG> used as the root for all filenames (i.e., "expected/$TAG.txt")
# <ARGS> command-line arguments to test
run_test C_simple_hex "-H inputs/simple.o"
run_test C_no_output "inputs/simple.o"
run_test B_help "-h"
run_test B_simple_full "-H inputs/simple.o"
run_test B_multisegment "-H inputs/multiseg.o"
run_test B_stripped "-H inputs/stripped.o"
run_test B_stack "-H inputs/stack.o"
run_test A_invalid_param "-x"
run_test A_invalid_multi_files "-H inputs/simple.o inputs/multiseg.o"
run_test A_invalid_multi_params "-H inputs/simple.o -H inputs/multiseg.o"
run_test A_missing_filename "-H"
run_test A_nonexistent_file "-H nonexist.o"
run_test A_bad_magic "-H inputs/bad-no_elf.o"
run_test A_short_header "-H inputs/bad-short_header.o"
run_test A_bad_magic_no_H "inputs/bad-no_elf.o"
run_test A_short_header_no_H "inputs/bad-short_header.o"

BIN
p1-check/tests/private.o Normal file

Binary file not shown.

26
p1-check/tests/public.c Normal file
View File

@@ -0,0 +1,26 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <check.h>
#include "../p1-check.h"
/* read_header is declared and defined */
START_TEST (C_sanity_read_header_is_declared)
{
elf_hdr_t elf;
FILE *fp = fopen ("inputs/simple.o", "r");
ck_assert (fp != NULL);
bool rc = read_header (fp, &elf);
ck_assert (rc || !rc);
}
END_TEST
void public_tests (Suite *s)
{
TCase *tc_public = tcase_create ("Public");
tcase_add_test (tc_public, C_sanity_read_header_is_declared);
suite_add_tcase (s, tc_public);
}

View File

@@ -0,0 +1,34 @@
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
#include <time.h>
#include <check.h>
extern void public_tests (Suite *s);
extern void private_tests (Suite *s);
Suite * test_suite (void)
{
Suite *s = suite_create ("Default");
public_tests (s);
private_tests (s);
return s;
}
void run_testsuite (void)
{
Suite *s = test_suite ();
SRunner *sr = srunner_create (s);
srunner_run_all (sr, CK_NORMAL);
srunner_free (sr);
}
int main (void)
{
srand((unsigned)time(NULL));
run_testsuite ();
return EXIT_SUCCESS;
}

BIN
p1-check/y86 Normal file

Binary file not shown.