diff --git a/lab6-memory/.gitignore b/lab6-memory/.gitignore new file mode 100644 index 0000000..399ec66 --- /dev/null +++ b/lab6-memory/.gitignore @@ -0,0 +1,2 @@ +build +.gdb_history diff --git a/lab6-memory/Makefile b/lab6-memory/Makefile new file mode 100644 index 0000000..5f48880 --- /dev/null +++ b/lab6-memory/Makefile @@ -0,0 +1,18 @@ +C := gcc +CXX := g++ + +build: + mkdir -p build + $(C) src/main.c -std=c17 -O0 \ + -Wall -Wextra -Werror \ + -fno-stack-protector -no-pie \ + -g \ + -o build/main + $(CXX) src/util.cpp -std=c++20 -O2 \ + -Wall -Wextra -Werror \ + -o build/util + +clean: + rm -rf build + +.PHONY: build clean diff --git a/lab6-memory/src/main.c b/lab6-memory/src/main.c new file mode 100644 index 0000000..ab4f362 --- /dev/null +++ b/lab6-memory/src/main.c @@ -0,0 +1,89 @@ +#include +#include +#include +#include +#include +#include +#include + +#define STACK_ARRAY_SIZE (1 << 15) // 32 KiB +#define HEAP_ARRAY_SIZE (1 << 25) // 32 MiB +#define THREAD_COUNT 2 + +pthread_mutex_t mutex_output; + +static inline void output(const char *fmt, ...) { + pthread_mutex_lock(&mutex_output); + + va_list args; + va_start(args, fmt); + vprintf(fmt, args); + putchar('\n'); + fflush(stdout); + va_end(args); + + pthread_mutex_unlock(&mutex_output); +} + +const char *string_literal_1 = "i will be put in the .rodata segment."; +const char *string_literal_2 = "i will be put in the .rodata segment."; +const char *string_literal_3 = "i will be the different one!"; +const int integer_constant = 42; + +int bss_integer; +double bss_real; + +int integer = 2022212720; +double real = 2022211363; + +static inline void easy_to_break() {} + +static inline void *task(void *arg) { + size_t id = *(size_t *)arg; + + int array_on_stack[STACK_ARRAY_SIZE]; + int *array_on_heap = malloc(HEAP_ARRAY_SIZE * sizeof(int)); + output("Thread %zu started, stack array address: %p, heap array address: %p", id, array_on_stack, array_on_heap); + + pthread_cleanup_push(free, array_on_heap); + + easy_to_break(); + + pthread_cleanup_pop(1); + pthread_exit(NULL); +} + +int main() { + pthread_mutex_init(&mutex_output, NULL); + int array_on_stack[STACK_ARRAY_SIZE]; + int *array_on_heap = malloc(HEAP_ARRAY_SIZE * sizeof(int)); + pthread_t threads[THREAD_COUNT]; + size_t ids[THREAD_COUNT]; + + output("Hello, World! My pid is %d", getpid()); + output("Stack array address: %p", array_on_stack); + output("Heap array address: %p", array_on_heap); + + output("Threads creating..."); + for (size_t i = 0; i < THREAD_COUNT; i++) { + ids[i] = i; + pthread_create(&threads[i], NULL, task, &ids[i]); + } + + easy_to_break(); + + output("Threads joining..."); + for (size_t i = 0; i < THREAD_COUNT; i++) { + pthread_cancel(threads[i]); + pthread_join(threads[i], NULL); + } + + output("Bye, World!"); + + free(array_on_heap), array_on_heap = NULL; + pthread_mutex_destroy(&mutex_output); + + easy_to_break(); + + return 0; +} diff --git a/lab6-memory/src/util.cpp b/lab6-memory/src/util.cpp new file mode 100644 index 0000000..4325123 --- /dev/null +++ b/lab6-memory/src/util.cpp @@ -0,0 +1,90 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +struct pagemap_entry_t { + uint64_t pfn : 55; + unsigned int soft_dirty : 1; + unsigned int file_page : 1; + unsigned int swapped : 1; + unsigned int present : 1; +}; + +static inline auto get_pagemap_entry(int pagemap_fd, uintptr_t page_number) -> pagemap_entry_t { + pagemap_entry_t entry; + size_t nread = 0; + uint64_t data; + while (nread < sizeof(data)) { + ssize_t result = pread(pagemap_fd, ((uint8_t *)&data) + nread, sizeof(data) - nread, page_number * sizeof(data) + nread); + if (result <= 0) { + std::cerr << "Failed to read pagemap file" << std::endl; + abort(); + } + nread += result; + } + + entry.pfn = data & ((1ull << 55) - 1); + entry.soft_dirty = (data >> 55) & 1; + entry.file_page = (data >> 61) & 1; + entry.swapped = (data >> 62) & 1; + entry.present = (data >> 63) & 1; + return entry; +} + +int main() { + pid_t pid; + std::cout << "Please input pid: " << std::endl; + std::cin >> pid; + + std::string pagemap_path = std::format("/proc/{}/pagemap", pid); + std::cout << pagemap_path << std::endl; + + int pagemap_fd = open(pagemap_path.c_str(), O_RDONLY); + if (pagemap_fd == -1) { + std::cerr << "Failed to open pagemap file" << std::endl; + abort(); + } + + auto get_physical_address = [&](size_t virtual_address) -> void { + const size_t page_size = sysconf(_SC_PAGESIZE); + + const size_t page_number = virtual_address / page_size, offset = virtual_address % page_size; + + const pagemap_entry_t entry = get_pagemap_entry(pagemap_fd, page_number); + + if (!entry.present) { + std::cerr << "Page not present" << std::endl; + return; + } + + std::cout + << std::format("frame_number = 0x{:016x}, soft_dirty = {}, file_page = {}, swapped = {}, present = {}", + static_cast(entry.pfn), + static_cast(entry.soft_dirty), + static_cast(entry.file_page), + static_cast(entry.swapped), + static_cast(entry.present)) + << std::endl; + + const size_t frame_number = entry.pfn; + const size_t physical_address = frame_number * page_size + offset; + + std::cout << std::format("Physical Address: 0x{:016x}\n", physical_address) << std::endl; + return; + }; + + while (true) { + size_t virtual_address; + std::cout << "Please input virtual address: " << std::endl; + std::cin >> std::hex >> virtual_address; + get_physical_address(virtual_address); + } + + close(pagemap_fd); + return 0; +}