# Embedded Systems Reverse Engineering
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)

## Week 6
Static Variables in Embedded Systems: Debugging and Hacking Static Variables w/ GPIO Input Basics

### Exercise 2: Reverse Engineer gpio_set_pulls with GDB

#### Objective
Use GDB to disassemble the `gpio_set_pulls` function, trace its register writes to identify the PADS_BANK0 hardware register it modifies, and document how the Pico 2 configures internal pull-up and pull-down resistors at the hardware level.

#### Prerequisites
- Completed Week 6 tutorial (GDB section)
- `0x0014_static-variables.elf` binary available in your build directory
- GDB (`arm-none-eabi-gdb`) and OpenOCD installed
- Understanding of GPIO pull-up resistors from Week 6 Part 2
- Understanding of function inlining from Week 6 Part 3

#### Task Description
You will use GDB to locate the `gpio_set_pulls` function (remember: `gpio_pull_up` is inlined and becomes `gpio_set_pulls`), disassemble it, step through it instruction by instruction, and identify the PADS_BANK0 register address it writes to. You will document the bit fields being set and explain how the hardware implements pull-up and pull-down resistors.

#### Step-by-Step Instructions

##### Step 1: Start the Debug Session

**Terminal 1 - Start OpenOCD:**

```bash
openocd ^
  -s "C:\Users\flare-vm\.pico-sdk\openocd\0.12.0+dev\scripts" ^
  -f interface/cmsis-dap.cfg ^
  -f target/rp2350.cfg ^
  -c "adapter speed 5000"
```

**Terminal 2 - Start GDB:**

```bash
arm-none-eabi-gdb build/0x0014_static-variables.elf
```

**Connect to target:**

```gdb
(gdb) target remote :3333
(gdb) monitor reset halt
```

##### Step 2: Find Where gpio_set_pulls is Called

From the tutorial, we know `gpio_set_pulls` is called at `0x1000024e` with arguments for GPIO 15:

```gdb
(gdb) x/5i 0x10000240
```

You should see:
```
0x10000240: movs r0, #15       ; GPIO pin 15
0x10000242: mov.w r3, #0        ; GPIO_IN (direction)
0x10000246: mcrr 0, 4, r0, r3, cr4  ; gpio_set_dir via coprocessor
0x1000024a: movs r2, #0        ; down = false
0x1000024c: movs r1, #1        ; up = true
0x1000024e: bl   0x100002d8    ; gpio_set_pulls
```

##### Step 3: Disassemble gpio_set_pulls

Now examine the function itself:

```gdb
(gdb) x/30i 0x100002d8
```

Study the disassembly carefully. Look for:
- Address calculations (base address of PADS_BANK0)
- Register loads and stores
- Bit manipulation instructions (AND, OR, BIC)
- The write to the hardware register

##### Step 4: Set a Breakpoint at gpio_set_pulls

```gdb
(gdb) b *0x100002d8
(gdb) monitor reset halt
(gdb) c
```

When the breakpoint hits, examine the arguments:

```gdb
(gdb) info registers r0 r1 r2
```

You should see:
- `r0 = 15` (GPIO pin)
- `r1 = 1` (pull-up enable)
- `r2 = 0` (pull-down disable)

##### Step 5: Step Through the Function

Use `si` (step instruction) to execute one instruction at a time:

```gdb
(gdb) si
(gdb) info registers
```

Repeat, watching the registers change. Pay attention to:

1. **Address calculation**: The function computes the PADS_BANK0 register address for GPIO 15. The base address is `0x40038000`, and each GPIO pad has a 4-byte register. GPIO 0 starts at offset `0x04`, so GPIO 15 is at:

$$0x40038000 + 0x04 + (15 \times 4) = 0x40038000 + 0x04 + 0x3C = 0x40038040$$

2. **Read the current register value**: The function reads the existing pad configuration
3. **Modify the pull bits**: It sets or clears the pull-up (bit 3) and pull-down (bit 2) bits
4. **Write back**: It stores the modified value

##### Step 6: Examine the PADS_BANK0 Register

After the function completes, examine the result:

```gdb
(gdb) x/1wx 0x40038040
```

Document the value you see. The relevant bits are:

| Bit | Name     | Value | Meaning                 |
| --- | -------- | ----- | ----------------------- |
| 3   | PUE      | 1     | Pull-up enable          |
| 2   | PDE      | 0     | Pull-down enable        |
| 1   | SCHMITT  | 1     | Schmitt trigger enabled |
| 0   | SLEWFAST | 0     | Slow slew rate          |

##### Step 7: Compare with gpio_set_pulls for the LED Pin

Continue execution until gpio_set_pulls is called again (if it is). Or, examine the pad register for GPIO 16 (the LED pin):

```gdb
(gdb) x/1wx 0x40038044
```

Compare the values. The LED pin (output) should NOT have pull-up enabled.

##### Step 8: Document Your Findings

Create a table documenting the function's behavior:

| Step                     | Instruction(s)     | Register Changes            |
| ------------------------ | ------------------ | --------------------------- |
| Load PADS base address   | `ldr rX, =...`     | rX = `0x40038000`           |
| Calculate pad offset     | `adds`, `lsls`     | offset = `0x04 + pin * 4`  |
| Read current pad config  | `ldr rX, [addr]`   | rX = current register value |
| Clear pull bits          | `bic rX, rX, #0xC` | Clear bits 2 and 3          |
| Set pull-up bit          | `orr rX, rX, #0x8` | Set bit 3 (PUE)            |
| Write back               | `str rX, [addr]`   | Updated pad register        |

#### Expected Output

After completing this exercise, you should be able to:
- Disassemble and trace through a hardware configuration function
- Identify PADS_BANK0 register addresses for any GPIO pin
- Understand how pull-up and pull-down resistors are controlled at the register level
- Explain why `gpio_pull_up(pin)` becomes `gpio_set_pulls(pin, true, false)` in the binary

#### Questions for Reflection

###### Question 1: Why does the function read-modify-write the register instead of just writing a new value? What would happen if it just wrote without reading first?

###### Question 2: The pad register for GPIO 15 is at offset `0x40` from the PADS base. How is this offset calculated? What would the offset be for GPIO 0?

###### Question 3: What would happen if you enabled BOTH pull-up and pull-down at the same time (bits 2 and 3 both set)?

###### Question 4: The compiler inlines `gpio_pull_up` into `gpio_set_pulls`. What does this tell you about the compiler's optimization level? How does inlining affect binary analysis?

#### Tips and Hints
- PADS_BANK0 base address on RP2350 is `0x40038000`
- Each GPIO has a 4-byte pad control register starting at offset `0x04`
- The `bic` instruction clears bits (Bit Clear); `orr` sets bits (OR)
- Use `x/1wx` to examine a 32-bit word; use `x/1tb` to see individual bits
- The RP2350 datasheet section on PADS_BANK0 has the full register bit map

#### Next Steps
- Proceed to Exercise 3 to reverse engineer the `eor` (XOR) instruction in the GPIO logic
- Try enabling pull-down instead of pull-up by modifying the `gpio_set_pulls` arguments in GDB: `set $r1 = 0` and `set $r2 = 1` before the function call
- Examine the PADS registers for all GPIOs to see which pins have pull-ups enabled after boot
