debug: gdbstub: add bits to restrict memory read/write
This adds bits for architectures, SoCs or boards to restrict memory access in GDB stub. This is mainly to make sure GDB stub only read/write to memory that can be legally accessed without resulting in memory faults. Signed-off-by: Daniel Leung <daniel.leung@intel.com>
This commit is contained in:
parent
650a629b08
commit
48da4dbb2a
2 changed files with 200 additions and 9 deletions
|
@ -15,6 +15,49 @@
|
||||||
#define GDB_EXCEPTION_INVALID_MEMORY 11UL
|
#define GDB_EXCEPTION_INVALID_MEMORY 11UL
|
||||||
#define GDB_EXCEPTION_OVERFLOW 16UL
|
#define GDB_EXCEPTION_OVERFLOW 16UL
|
||||||
|
|
||||||
|
/* Access permissions for memory regions */
|
||||||
|
#define GDB_MEM_REGION_NO_ACCESS 0UL
|
||||||
|
#define GDB_MEM_REGION_READ BIT(0)
|
||||||
|
#define GDB_MEM_REGION_WRITE BIT(1)
|
||||||
|
|
||||||
|
#define GDB_MEM_REGION_RO \
|
||||||
|
(GDB_MEM_REGION_READ)
|
||||||
|
|
||||||
|
#define GDB_MEM_REGION_RW \
|
||||||
|
(GDB_MEM_REGION_READ | GDB_MEM_REGION_WRITE)
|
||||||
|
|
||||||
|
/** Describe one memory region */
|
||||||
|
struct gdb_mem_region {
|
||||||
|
/** Start address of a memory region */
|
||||||
|
uintptr_t start;
|
||||||
|
|
||||||
|
/** End address of a memory region */
|
||||||
|
uintptr_t end;
|
||||||
|
|
||||||
|
/** Memory region attributes */
|
||||||
|
uint16_t attributes;
|
||||||
|
|
||||||
|
/** Read/write alignment, 0 if using default alignment */
|
||||||
|
uint8_t alignment;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Memory region descriptions used for GDB memory access.
|
||||||
|
*
|
||||||
|
* This array specifies which region of memory GDB can access
|
||||||
|
* with read/write attribites. This is used to restrict
|
||||||
|
* memory read/write in GDB stub to memory that can be
|
||||||
|
* legally accessed without resulting in memory faults.
|
||||||
|
*/
|
||||||
|
extern const struct gdb_mem_region gdb_mem_region_array[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of Memory Regions.
|
||||||
|
*
|
||||||
|
* Number of elements in gdb_mem_region_array[];
|
||||||
|
*/
|
||||||
|
extern const size_t gdb_mem_num_regions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Convert a binary array into string representation.
|
* @brief Convert a binary array into string representation.
|
||||||
*
|
*
|
||||||
|
@ -31,4 +74,31 @@
|
||||||
size_t gdb_bin2hex(const uint8_t *buf, size_t buflen,
|
size_t gdb_bin2hex(const uint8_t *buf, size_t buflen,
|
||||||
char *hex, size_t hexlen);
|
char *hex, size_t hexlen);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if a memory block can be read.
|
||||||
|
*
|
||||||
|
* This checks if the specified memory block can be read.
|
||||||
|
*
|
||||||
|
* @param[in] addr Starting address of the memory block
|
||||||
|
* @param[in] len Size of memory block
|
||||||
|
* @param[out] align Read alignment of region
|
||||||
|
*
|
||||||
|
* @return True if memory block can be read, false otherwise.
|
||||||
|
*/
|
||||||
|
bool gdb_mem_can_read(const uintptr_t addr, const size_t len, uint8_t *align);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if a memory block can be written into.
|
||||||
|
*
|
||||||
|
* This checks if the specified memory block can be written into.
|
||||||
|
*
|
||||||
|
* @param[in] addr Starting address of the memory block
|
||||||
|
* @param[in] len Size of memory block
|
||||||
|
* @param[out] align Write alignment of region
|
||||||
|
*
|
||||||
|
* @return True if GDB stub can write to the block, false otherwise.
|
||||||
|
*/
|
||||||
|
bool gdb_mem_can_write(const uintptr_t addr, const size_t len, uint8_t *align);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -17,8 +17,11 @@ LOG_MODULE_REGISTER(gdbstub);
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <toolchain.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/util.h>
|
||||||
|
|
||||||
|
#include <debug/gdbstub.h>
|
||||||
#include "gdbstub_backend.h"
|
#include "gdbstub_backend.h"
|
||||||
|
|
||||||
/* +1 is for the NULL character added during receive */
|
/* +1 is for the NULL character added during receive */
|
||||||
|
@ -35,6 +38,107 @@ LOG_MODULE_REGISTER(gdbstub);
|
||||||
|
|
||||||
static bool not_first_start;
|
static bool not_first_start;
|
||||||
|
|
||||||
|
/* Empty memory region array */
|
||||||
|
__weak const struct gdb_mem_region gdb_mem_region_array[0];
|
||||||
|
|
||||||
|
/* Number of memory regions, default to 0 */
|
||||||
|
__weak const size_t gdb_mem_num_regions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a starting address and length of a memory block, find a memory
|
||||||
|
* region descriptor from the memory region array where the memory block
|
||||||
|
* fits inside the memory region.
|
||||||
|
*
|
||||||
|
* @param addr Starting address of the memory block
|
||||||
|
* @param len Length of the memory block
|
||||||
|
*
|
||||||
|
* @return Pointer to the memory region description if found.
|
||||||
|
* NULL if not found.
|
||||||
|
*/
|
||||||
|
static inline const
|
||||||
|
struct gdb_mem_region *find_memory_region(const uintptr_t addr, const size_t len)
|
||||||
|
{
|
||||||
|
const struct gdb_mem_region *r, *ret = NULL;
|
||||||
|
unsigned int idx;
|
||||||
|
|
||||||
|
for (idx = 0; idx < gdb_mem_num_regions; idx++) {
|
||||||
|
r = &gdb_mem_region_array[idx];
|
||||||
|
|
||||||
|
if ((addr >= r->start) &&
|
||||||
|
(addr < r->end) &&
|
||||||
|
((addr + len) >= r->start) &&
|
||||||
|
((addr + len) < r->end)) {
|
||||||
|
ret = r;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool gdb_mem_can_read(const uintptr_t addr, const size_t len, uint8_t *align)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
const struct gdb_mem_region *r;
|
||||||
|
|
||||||
|
if (gdb_mem_num_regions == 0) {
|
||||||
|
/*
|
||||||
|
* No region is defined.
|
||||||
|
* Assume memory access is not restricted, and there is
|
||||||
|
* no alignment requirement.
|
||||||
|
*/
|
||||||
|
*align = 1;
|
||||||
|
ret = true;
|
||||||
|
} else {
|
||||||
|
r = find_memory_region(addr, len);
|
||||||
|
if (r != NULL) {
|
||||||
|
if ((r->attributes & GDB_MEM_REGION_READ) ==
|
||||||
|
GDB_MEM_REGION_READ) {
|
||||||
|
if (r->alignment > 0) {
|
||||||
|
*align = r->alignment;
|
||||||
|
} else {
|
||||||
|
*align = 1;
|
||||||
|
}
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool gdb_mem_can_write(const uintptr_t addr, const size_t len, uint8_t *align)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
const struct gdb_mem_region *r;
|
||||||
|
|
||||||
|
if (gdb_mem_num_regions == 0) {
|
||||||
|
/*
|
||||||
|
* No region is defined.
|
||||||
|
* Assume memory access is not restricted, and there is
|
||||||
|
* no alignment requirement.
|
||||||
|
*/
|
||||||
|
*align = 1;
|
||||||
|
ret = true;
|
||||||
|
} else {
|
||||||
|
r = find_memory_region(addr, len);
|
||||||
|
if (r != NULL) {
|
||||||
|
if ((r->attributes & GDB_MEM_REGION_WRITE) ==
|
||||||
|
GDB_MEM_REGION_WRITE) {
|
||||||
|
if (r->alignment > 0) {
|
||||||
|
*align = r->alignment;
|
||||||
|
} else {
|
||||||
|
*align = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
size_t gdb_bin2hex(const uint8_t *buf, size_t buflen, char *hex, size_t hexlen)
|
size_t gdb_bin2hex(const uint8_t *buf, size_t buflen, char *hex, size_t hexlen)
|
||||||
{
|
{
|
||||||
if ((hexlen + 1) < buflen * 2) {
|
if ((hexlen + 1) < buflen * 2) {
|
||||||
|
@ -159,18 +263,24 @@ static int gdb_get_packet(uint8_t *buf, size_t buf_len, size_t *len)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read data from a given memory.
|
* Read data from a given memory address and length.
|
||||||
*
|
*
|
||||||
* Return 0 in case of success, otherwise -1
|
* @return Number of bytes read from memory, otherwise -1
|
||||||
*/
|
*/
|
||||||
static int gdb_mem_read(uint8_t *buf, size_t buf_len,
|
static int gdb_mem_read(uint8_t *buf, size_t buf_len,
|
||||||
uintptr_t addr, size_t len)
|
uintptr_t addr, size_t len)
|
||||||
{
|
{
|
||||||
uint8_t data;
|
uint8_t data, align;
|
||||||
size_t pos, count = 0;
|
size_t pos, count = 0;
|
||||||
|
|
||||||
if (len > buf_len) {
|
if (len > buf_len) {
|
||||||
return -1;
|
count = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gdb_mem_can_read(addr, len, &align)) {
|
||||||
|
count = -1;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read from system memory */
|
/* Read from system memory */
|
||||||
|
@ -179,24 +289,32 @@ static int gdb_mem_read(uint8_t *buf, size_t buf_len,
|
||||||
count += gdb_bin2hex(&data, 1, buf + count, buf_len - count);
|
count += gdb_bin2hex(&data, 1, buf + count, buf_len - count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write data in a given memory.
|
* Write data to a given memory address and length.
|
||||||
*
|
*
|
||||||
* Return 0 in case of success, otherwise -1
|
* @return 0 if successful, otherwise -1
|
||||||
*/
|
*/
|
||||||
static int gdb_mem_write(const uint8_t *buf, uintptr_t addr,
|
static int gdb_mem_write(const uint8_t *buf, uintptr_t addr,
|
||||||
size_t len)
|
size_t len)
|
||||||
{
|
{
|
||||||
uint8_t data;
|
uint8_t data, align;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!gdb_mem_can_write(addr, len, &align)) {
|
||||||
|
ret = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
while (len > 0) {
|
while (len > 0) {
|
||||||
size_t ret = hex2bin(buf, 2, &data, sizeof(data));
|
size_t ret = hex2bin(buf, 2, &data, sizeof(data));
|
||||||
|
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
return -1;
|
ret = -1;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
*(uint8_t *)addr = data;
|
*(uint8_t *)addr = data;
|
||||||
|
@ -206,7 +324,10 @@ static int gdb_mem_write(const uint8_t *buf, uintptr_t addr,
|
||||||
len--;
|
len--;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
ret = 0;
|
||||||
|
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue