Skip to content

Commit

Permalink
memory-layout/memory-operations-and-GDB: Add reading and tasks
Browse files Browse the repository at this point in the history
Add reading and tasks for lab 2 and modify config.yaml to render the new
content.

Signed-off-by: Adrian-George Dumitrache <[email protected]>
  • Loading branch information
dumitrache-adrian92 committed Mar 2, 2024
1 parent cc014bf commit c687bf4
Show file tree
Hide file tree
Showing 54 changed files with 1,532 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Data Inspection

You will solve the exercise starting from the `inspect.c` file located in the `drills/tasks/inspect/support` directory.

Given the following declarations:

```c
#include <stdio.h>

int main() {
unsigned int a = 4127;
int b = -27714;
short c = 1475;
int v[] = {0xCAFEBABE, 0xDEADBEEF, 0x0B00B135, 0xBAADF00D, 0xDEADC0DE};

unsigned int *int_ptr = (unsigned int *) &v;

for (int i = 0 ; i < sizeof(v) / sizeof(*int_ptr) ; ++i) {
++int_ptr;
}

return 0;
}
```

Compile the source code and run the executable with GDB.
Set a breakpoint at `main` and observe how the data is represented in memory.
For this task, you will use the `print` and `examine` commands.

> **NOTE:**
>
> - To display the value of a variable in hexadecimal, use `p/x variable_name`
> - To display the value from a pointer, use `p *pointer_name`, and to inspect the data at a memory address, use `x memory_address`.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/inspect
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
CC = gcc
CFLAGS = -Wall -g
LDFLAGS =

TARGET_EXEC = inspect

SRCS := $(shell find $(SRC_DIRS) -name "*.c")
OBJS := $(SRCS:.c=.o)

$(info OBJS is $(OBJS))
$(info SRCS is $(SRCS))

$(TARGET_EXEC): $(OBJS)
$(CC) $(OBJS) -o $@ $(LDFLAGS)

.o: %.c
$(CC) $(CFLAGS) $(LDFLAGS) -c $< -o $@

.PHONY: clean

clean:
$(RM) -r *.o $(TARGET_EXEC)
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: BSD-3-Clause

#include <stdio.h>

int main(void)
{
unsigned int a = 4127;
int b = -27714;
short c = 1475;
int v[] = {0xCAFEBABE, 0xDEADBEEF, 0x0B00B135, 0xBAADF00D, 0xDEADC0DE};

unsigned int *int_ptr = (unsigned int *) &v;

for (unsigned int i = 0 ; i < sizeof(v) / sizeof(*int_ptr) ; ++i)
++int_ptr;

(void) a;
(void) b;
(void) c;

return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# GDB Tutorial: Debugging a Segfault

You will solve the exercise starting from the `segfault.c` file located in the `drills/tasks/segfault/support` directory.

Compile and run the source code from the skeleton (if you are not using the Makefile, make sure to compile with the -g flag).
In short, the program takes a number n, allocates a vector of size n, and initializes it with the first n numbers from the Fibonacci sequence.
However, after running the program, you see: Segmentation fault (core dumped).

Start GDB with the executable:

```bash
gdb ./segfault
```

Once you have started GDB, all interaction happens through the GDB prompt.
Run the program using the `run` command.
What do you notice?
GDB hangs at the input reads.

Set a breakpoint at `main` using the `break main` command.
You will see the message in the prompt:

```c
Breakpoint 1 at 0x7d3: file seg.c, line 21 /* The memory address should not be the same */
```

Next, we will step through the instructions one by one.
To do this, use the `next` or `n` command (watch the GDB cursor to see the current instruction and repeat the process).
You will notice that GDB hangs at `scanf`, so input a value for `n` and continue stepping through.
If you have entered a large value for `n` and want to skip the iteration, use the `continue` command.
Eventually, you will reach the line `v[423433] = 3;`, and GDB will display:

```bash
Program received signal SIGSEGV, Segmentation fault
```

Inspect the memory at `v[423433]` using `x &v[423433]` and you will receive the message:

```c
Cannot access memory at address 0x5555558f3e94 /* The memory address should not be the same */
```

What happened?
We accessed a memory area with restricted access.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/segfault
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
CC = gcc
CFLAGS = -Wall -g
LDFLAGS =

TARGET_EXEC = segfault

SRCS := $(shell find $(SRC_DIRS) -name "*.c")
OBJS := $(SRCS:.c=.o)

$(info OBJS is $(OBJS))
$(info SRCS is $(SRCS))

$(TARGET_EXEC): $(OBJS)
$(CC) $(OBJS) -o $@ $(LDFLAGS)

.o: %.c
$(CC) $(CFLAGS) $(LDFLAGS) -c $< -o $@

.PHONY: clean

clean:
$(RM) -r *.o $(TARGET_EXEC)
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// SPDX-License-Identifier: BSD-3-Clause

#include <stdio.h>
#include <stdlib.h>

int nth_fibo(const int n)
{
if (n == 1 || n == 2)
return 1;

int first = 1, second = 1, nth_fib = 0;

for (int i = 3 ; i <= n ; ++i) {
nth_fib = first + second;
first = second;
second = nth_fib;
}

return nth_fib;
}

int main(void)
{
int n;

scanf("%d", &n);
int *v = malloc(n * sizeof(*v));

for (int i = 0 ; i < n; ++i)
v[i] = nth_fibo(i);

v[423433] = 3;
free(v);

return 0;
}
83 changes: 83 additions & 0 deletions chapters/memory-layout/introduction-to-GDB/reading/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# GNU Debugger (GDB)

## Starting GDB

GDB is a powerful tool for debugging programs.
It allows you to inspect the state of a program at a certain point in its execution, set breakpoints, and step through the code, among other things.
To start GDB, you need to run the following command:

```bash
gdb [program_name]
```

## Running the Program

To run the program being debugged, there are two available commands:

- `r` or `run` - this command will run the program
- `start` - unlike `run`, this command will start the program but immediately stop after entering `main`

## Breakpoints

The essential element of GDB is the breakpoint.
Essentially, setting a breakpoint at a certain instruction causes the program's execution to halt every time it reaches that point.
Setting a breakpoint is done with the following command:

```gdb
break [location]
```

where *location* can represent the name of a function, the line number of the code, or even a memory address, in which case the address must be preceded by the symbol *.
For example: `break \*0xCAFEBABE`

## Stepping through instructions

- `si` or `stepi` - executes the current instruction
- `ni` or `nexti` - similar to `stepi`, but if the current instruction is a function call, the debugger will not enter the function
- `c` or `continue` - continues program execution until the next breakpoint or until it finishes
- `finish` - continues program execution until leaving the current function

## Inspecting Memory

- `p` or `print` var - displays the value of `var`.
Print is a very flexible command, allowing dereferencing of pointers, displaying addresses of variables, and indexing through arrays using *, & and [].
The print command can be followed by the /f parameter specifying the display format (x for hex, d for decimal, s for string).
- `x` or `examine` - Inspects the content at the given address.
The usage of this command is as follows:

```text
x/nfu address
```

where:

- n is the number of displayed elements
- f is the display format (x for hex, d for decimal, s for string, and i for instructions)
- u is the size of each element (b for 1 byte, h for 2, w for 4, and g for 8 bytes)

We recommend the article [Debugging](https://ocw.cs.pub.ro/courses/programare/tutoriale/debugging) for further understanding of how to use GDB both in the CLI and through an IDE.

## pwndbg

[pwndbg](https://github.com/pwndbg/pwndbg) is a GDB plugin that provides a number of useful features for debugging and exploiting binaries.
It makes GDB easier to use and infinitely more powerful. It will become more useful as we progress through the lab sessions.

Cheatsheet [gdb + pwndbg](https://cheatography.com/superkojiman/cheat-sheets/gdb-pwndbg/); pwndbg [features](https://github.com/pwndbg/pwndbg/blob/dev/FEATURES.md)

```pwndbg
pwndbg> show context-sections
'regs disasm code ghidra stack backtrace expressions'
# for smaller terminals
pwndbg> set context-sections 'regs code stack'
# display memory area in hex + ASCII
pwndbg> hexdump $ecx
# display stack
pwndbg> stack
# permanently display memory dump of 8 bytes
pwndbg> ctx-watch execute "x/8xb &msg"
# recommended settings in .gdbinit
set context-sections 'regs code expressions'
set show-flags on
set dereference-limit 1
```
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/array_vs_pointer
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
CC = gcc
CFLAGS = -Wall -g
LDFLAGS =

TARGET_EXEC = array_vs_pointer

SRCS := $(shell find $(SRC_DIRS) -name "*.c")
OBJS := $(SRCS:.c=.o)

$(info OBJS is $(OBJS))
$(info SRCS is $(SRCS))

$(TARGET_EXEC): $(OBJS)
$(CC) $(OBJS) -o $@ $(LDFLAGS)

.o: %.c
$(CC) $(CFLAGS) $(LDFLAGS) -c $< -o $@

.PHONY: clean

clean:
$(RM) -r *.o $(TARGET_EXEC)
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: BSD-3-Clause

#include <stdio.h>

char v[] = "ana are mere";
char *p = "ana are mere";

int main(void)
{
printf("sizeof(v): %zu\n", sizeof(v));
printf("sizeof(p): %zu\n", sizeof(p));

printf("v[1]: %c\n", v[1]);
printf("p[1]: %c\n", p[1]);

v[1] = 'd';
// p[1] = 'd'; /* this seg faults */

return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Deleting the First Occurrence of a Pattern from a String

You will solve the exercise starting from the `delete-first.c` file located in the `drills/tasks/delete-first/support` directory.

Given a string and a pattern, implement the `delete_first(char *s, char *pattern)` function that returns the string obtained by removing the first occurrence of the pattern in `s`.

> **NOTE:** For `s = "Ana are mere"` and `pattern = "re"`, the function should return the string "Ana a mere".
>
> **IMPORTANT:** Warning
>
> ```c
> char *s = "Ana are mere" // allocates the string in a read-only memory area (immutable content);
> char s[] = "Ana are mere" // allocates the string in a read-write memory area (modifiable content);
> ```
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/delete_first
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// SPDX-License-Identifier: BSD-3-Clause

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>

char *delete_first(char *s, char *pattern)
{
char *found = strstr(s, pattern);

/**
* Handle the case where the pattern does not appear in the
* string of characters.
*/
if (!found)
return strdup(s);

/* number of characters before the first occurrence of the pattern */
int nbefore = found - s;
/* number of characters to be removed */
int nremoved = strlen(pattern);
/* Allocate exactly what we need. */
char *result = malloc(strlen(s) + 1 - nremoved);

/* Check if the allocation worked */
if (result == NULL) {
perror("malloc");
exit(1);
}

/* Construct the result */
strncpy(result, s, nbefore);
strcpy(result + nbefore, found + nremoved);

return result;
}

int main(void)
{
/**
* Replace *s with s[], because *s allocated the string in a
* read-only memory area (.rodata), and the delete_first() function
* needs to modify the string s
*/
char s[] = "Ana are mere";
char *pattern = "re";

printf("%s\n", delete_first(s, pattern));

return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/delete_first
Loading

0 comments on commit c687bf4

Please sign in to comment.