Solutions for all five summative questions: ELF binary investigation, x86-64 assembly file analysis, a Python C extension, a multithreaded producer–consumer system, and a concurrent TCP client–server booking system.
- Repository: https://github.com/Goodluck-dc14/Linux_Summative_Project
- Author: Ihuoma Goodluck Ogbonna
- Presentation https://youtu.be/XuG9DWGSEWE
- Full technical report: see
Linux_Summative_IhuomaGoodluckOgbonna.pdf(static/dynamic analysis, assembly-to-C reconstruction, synchronization design, protocol description, and screenshots of the concurrent client sessions).
| File | Project | What it is |
|---|---|---|
q1.c |
Q1 | C source for the ELF investigation program |
program |
Q1 | Compiled and stripped executable (the analysis target) |
q1_strace.txt |
Q1 | Captured strace system-call trace used in the report |
q2.asm |
Q2 | x86-64 GNU-assembler source (fully commented) |
q2 |
Q2 | Assembled/linked executable |
sensor_readings.txt |
Q2 | Sample input: 8 lines, 2 of them blank |
q3_sensor_analysis.c |
Q3 | C source for the sensor_analysis Python extension |
setup.py |
Q3 | Build script (setuptools) for the extension |
q3_test.py |
Q3 | Test program: exercises every function + invalid inputs |
sensor_analysis.*.so |
Q3 | Pre-built extension module (regenerated by setup.py) |
q4.c |
Q4 | Multithreaded producer–consumer–monitor source |
q4 |
Q4 | Compiled executable |
q4_sample_output.txt |
Q4 | Captured run showing the full 20-order lifecycle |
q5_server.c |
Q5 | Concurrent TCP server (thread-per-client) |
q5_client.c |
Q5 | TCP client |
q5_server / q5_client |
Q5 | Compiled executables |
q5_sample_output.txt |
Q5 | Captured client sessions (auth, reserve, conflict) |
q5_server_log.txt |
Q5 | Server status log showing connected users + reservation state |
README.md |
— | This file |
Prebuilt binaries are included for convenience; every one can be rebuilt from source with the commands below. An unstripped
program_debugfor Q1 GDB work is not shipped — build it on demand (see Q1).
Linux or WSL (Ubuntu/Debian assumed). Install the full toolchain in one step:
sudo apt update
sudo apt install -y build-essential binutils python3 python3-dev strace gdbThis provides gcc, as, ld, readelf, objdump, strip (binutils),
python3 + development headers (needed to build the C extension), plus
strace and gdb for the Q1 dynamic analysis.
gcc -Wall -O0 -fno-inline -o program q1.c && strip program # Q1
as --64 -o q2.o q2.asm && ld -o q2 q2.o # Q2
python3 setup.py build_ext --inplace # Q3
gcc -Wall -O2 -pthread -o q4 q4.c # Q4
gcc -Wall -O2 -pthread -o q5_server q5_server.c # Q5 server
gcc -Wall -O2 -o q5_client q5_client.c # Q5 clientWhat it does. A sensor-batch summary program written specifically to exercise
every structural element the analysis requires, then compiled and stripped so it
can be reverse-engineered with readelf, objdump, strace, and gdb.
How it satisfies the requirements:
| Requirement | Where |
|---|---|
3 user-defined functions (besides main) |
compute_sum, classify_reading, print_summary |
| ≥1 global variable | g_threshold = 50 |
| One loop | for loops in compute_sum and main |
| One decision statement | if/else in classify_reading |
| Dynamic allocation | malloc of 5 ints in main, freed with free |
| Standard-library call | printf / puts, malloc / free |
| Meaningful output | batch summary printed to the terminal |
Build and strip
gcc -Wall -O0 -fno-inline -o program q1.c
strip program
./programExpected output
Sensor batch summary
Readings processed: 5
Total: 275
Above threshold (50): 3
Input is fixed ({42, 67, 55, 31, 80}, threshold 50); no user input.
Key analysis findings (full detail in the report): 64-bit x86-64, built as a
Position-Independent Executable (Type: DYN), dynamically linked against
libc.so.6, entry point 0x10e0 (_start), stripped of its symbol table.
Analysis commands
readelf -h program # header: class, machine, type, entry point
readelf -S program # sections: .text .data .bss .plt .got ...
readelf -d program # dynamic section: NEEDED libc.so.6, BIND_NOW
objdump -d program # disassembly for function reconstruction
strace ./program # runtime system callsFor readable symbols in GDB, build an unstripped copy first:
gcc -Wall -O0 -fno-inline -g -o program_debug q1.c
gdb ./program_debug
# (gdb) starti / break main / break compute_sum / run / backtrace
# (gdb) print g_threshold / x/5d readings / print totalWhat it does. A freestanding x86-64 program (raw Linux syscalls, no libc) that
opens sensor_readings.txt, reads it into a buffer, and walks it byte by byte to
count total lines and valid (non-empty) lines. The source is fully commented,
explaining the file syscalls, the counting logic, and each control-flow branch.
How it satisfies the requirements: file open/read/close via syscalls;
loop-based byte traversal (process_loop); conditional logic for line boundaries,
empty lines, and valid data; correct handling of both LF (\n) and
CRLF (\r\n) endings (handle_cr look-ahead); error handling for open and
read failures; clean exit on every path.
Build and run
as --64 -o q2.o q2.asm
ld -o q2 q2.o
./q2Expected output (with the provided sample file — 8 lines, 2 blank)
Total records: 8
Valid records: 6
Error cases
Error: cannot open sensor_readings.txt # file missing/unreadable (exit 1)
Error: failed to read file # read() failure (exit 1)
What it does. A native CPython extension written entirely against the Python
C API. All numerical work is done in C using double; inputs are validated;
empty datasets and wrong types raise proper Python exceptions; no unnecessary
heap allocation is performed (single-pass accumulators on the stack).
Functions
| Function | Returns |
|---|---|
average(data) |
arithmetic mean |
range_value(data) |
max − min |
variance(data) |
sample variance (÷ n − 1) |
count_above(data, limit) |
count of values strictly > limit |
statistics(data) |
dict: samples, average, minimum, maximum |
Accepts a Python list or tuple of numbers. Empty input → ValueError;
non-sequence or non-numeric element → TypeError.
Build and test
python3 setup.py build_ext --inplace
python3 q3_test.pyq3_test.py calls every function on sample data and then triggers the empty,
wrong-type, and non-numeric error paths.
Interactive example
import sensor_analysis
data = [12.5, 18.0, 21.3, 16.7, 19.8, 22.1, 14.4]
print(sensor_analysis.average(data))
print(sensor_analysis.statistics(data))What it does. Simulates a food-delivery pipeline with three POSIX threads
sharing a fixed-capacity (5) circular queue: a kitchen producer (one order
every 2 s), a delivery consumer (one delivery every 4 s), and a monitor
(status every 5 s). Shared state is protected by one pthread_mutex_t and
coordinated with two pthread_cond_t variables (not_full, not_empty).
Synchronization guarantees: queue capacity is never exceeded; the consumer
never dequeues an empty queue; the monitor reads shared counters under the lock
without racing. Shutdown is graceful — after 20 orders the kitchen sets
production_done and broadcasts not_empty; the delivery and monitor threads
detect completion and exit, and main joins all three.
Compile and run
gcc -Wall -O2 -pthread -o q4 q4.c
./q4Expected output pattern (full capture in q4_sample_output.txt)
Order processing system started (queue capacity = 5, total orders = 20)
[Kitchen] Prepared order 1 | Queue size: 1
[Delivery] Starting delivery for order 1 | Queue size: 0
[Monitor] Orders prepared: X | Orders delivered: Y | Current Queue size: Z
[Kitchen] Queue full. Waiting...
[Delivery] Queue empty. Waiting...
All orders processed. System shutting down.
A full run takes ~80 s because delivery (4 s) is slower than preparation (2 s),
so the queue fills to 5 and the kitchen blocks on not_full partway through.
What it does. A concurrent lab-equipment booking system. The server accepts
multiple simultaneous clients (thread-per-client, pthread_create +
pthread_detach), authenticates against a fixed user list, sends the equipment
list, and lets an authenticated user reserve one item. All shared state
(user flags, connected count, equipment table) is guarded by a single
pthread_mutex_t, so two clients cannot reserve the same item.
Compile and run
gcc -Wall -O2 -pthread -o q5_server q5_server.c
gcc -Wall -O2 -o q5_client q5_client.c
./q5_server # terminal 1 — listens on TCP port 5050
./q5_client # terminal 2 (or ./q5_client 127.0.0.1)Valid users: STU001, STU002, RES001, RES002, LABADMIN
Client flow: enter user ID → view equipment → choose item 1–5 → receive
result → session closes with Session closed. Goodbye, <USER_ID>.
Example results (full captures in q5_sample_output.txt / q5_server_log.txt)
AUTH_FAIL: Unauthorized user
RESERVE_OK: Microscope-A reserved successfully for STU001
RESERVE_FAIL: Microscope-A is already reserved by STU001
To demonstrate concurrency, open at least five client terminals (one per user) at the same time; the server log shows connected users climbing to 5 with a consistent reservation table throughout.
Notes: if the server reports the port is in use, either wait for the socket to clear or change the port constant and rebuild. Unexpected client disconnects are handled per-thread and never crash the accept loop.
-
q1.cand strippedprogram(+q1_strace.txt) -
q2.asm(commented) andsensor_readings.txt -
q3_sensor_analysis.c,setup.py,q3_test.py -
q4.c(+q4_sample_output.txt) -
q5_server.c,q5_client.c(+q5_sample_output.txt,q5_server_log.txt) - This README
- Full technical report (
Linux_Summative_Full_Report.docx) - Presentation recording — Video in the document as a link