Hey, struggling to think about all thingz that I need to complete, I made up my mind to write a debugging interface. So here I am with 2 questions: (especially to gurus, dont get me wrong all ideas are welcome but I know that some gurus have already implemented debugging interfaces )
1) What does debugging interface consist of? I mean is there a standard? What have you implemented in it? (if you have implemented one of course.)
2) A very first thing that I can think of is checking memory writes and reads under software control, particularly I want to protect areas like memory bitmap, page tables, page directories from malicious or careless pointers. How can I check if a write or read is done to or from one of these reserved areas? I know you say check pointer value but is there a more easy way to check this?
Thanx...
debugging interface
Re:debugging interface
Depends what you need. Mine is a command line interface which lets me inspect what needs inspecting. I add new commands as I find new bugs.Ozguxxx wrote:1) What does debugging interface consist of? I mean is there a standard? What have you implemented in it? (if you have implemented one of course.)
Better to add write protection and access control as needed -- you can't realistically pass all reads and writes through software, just in case one of them writes over your memory allocation structures.2) A very first thing that I can think of is checking memory writes and reads under software control, particularly I want to protect areas like memory bitmap, page tables, page directories from malicious or careless pointers. How can I check if a write or read is done to or from one of these reserved areas? I know you say check pointer value but is there a more easy way to check this?
One way to strengthen things is to add guard pages around vital structures. A guard page is an unmapped page which is certain to trigger a fault at a well-known address if accessed. For example, Mobius puts a guard page at the end of each kernel stack to detect stack overflows. It wastes 4KB of address space, though, so you shouldn't use guard pages for smaller structures.
Re:debugging interface
I'm not sure that's what Ozguxxx asked for.
Ozguxxx, when you say "debugging interface", do you mean user interface, or binary interface? If the latter, you might want to do a Google on DWARF 2 / DWARF 3.
As for memory access, that severly depends on the memory management policy of your operating system.
That could be single-address-space, unprotected memory, which makes detecting rogue pointers pretty hard. The tools Enforcer and Mungwall handle parts of this under AmigaOS (which runs on unprotected memory); I don't know if they are open source, documented, or even available, but Aminet (www.aminet.net) could be a starting point.
On the other hand of the scale, that could be a policy that uses IA-32 segmented memory with lots of special segments, which would make pointer violations really easy to detect (since they would violate the segmentation).
Ozguxxx, when you say "debugging interface", do you mean user interface, or binary interface? If the latter, you might want to do a Google on DWARF 2 / DWARF 3.
As for memory access, that severly depends on the memory management policy of your operating system.
That could be single-address-space, unprotected memory, which makes detecting rogue pointers pretty hard. The tools Enforcer and Mungwall handle parts of this under AmigaOS (which runs on unprotected memory); I don't know if they are open source, documented, or even available, but Aminet (www.aminet.net) could be a starting point.
On the other hand of the scale, that could be a policy that uses IA-32 segmented memory with lots of special segments, which would make pointer violations really easy to detect (since they would violate the segmentation).
Every good solution is obvious once you've found it.
Re:debugging interface
I am asking exactly for what Tim Robinson's telling about. simply I need some debuggign function calls to find where error is, as code gets bigger and more things are going into it, I become more paranoid about bugs. So I need some more info than to see where can code goes just by printing some strings... Hope this makes question clearer. BTW, Guard pages is a good idea, although it means waste of memory.
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:debugging interface
from my experience, with a good programming style, miscomputed pointers are quite uncommon while null (or worse, floating) pointers are very common. So if you enforce yourself to initialize any pointer (and NULLify them when needed) and let the 0 page absent (or make the data segment expand-down with a limit of 4Gb-4Kb, depending on what's easiest for your design) and use page guards to avoid stack-overflows, you should catch most programming bugs.
A thing that also helps alot is the use of "magic words" that may help you identify what is where. For instance, in Clicker, every allocated block has a 4 bytes "BLOC" tag at block-8 and the size at block-4, so i can easily know if a pointer points to some valid allocated memory by just looking a few bytes.
You can even push this one step further by replacing "BLOC" by some constructor-specific tag. For instance
A thing that also helps alot is the use of "magic words" that may help you identify what is where. For instance, in Clicker, every allocated block has a 4 bytes "BLOC" tag at block-8 and the size at block-4, so i can easily know if a pointer points to some valid allocated memory by just looking a few bytes.
You can even push this one step further by replacing "BLOC" by some constructor-specific tag. For instance
Code: Select all
#define FILE_TAG 0x656c6946; // this should read as "File" in a memory watcher
FileHandle* FileHandleCtor()
{
FileHandle *FH=kalloc(sizeof(FileHandle));
#ifdef __PARANOIA__
dword* tag=((dword*)FH)-2;
*tag=FILE_TAG;
#endif
return FH;
}
FileOperation(FileHandle *f)
{
#ifdef __PARANOIA__
if (*((dword*)f)-2)!=FILE_TAG) panic("%x is not a file handle",f);
#endif
...
}
FileDtor(FileHandle *f)
{
#ifdef __PARANOIA__
if (*((dword*)f)-2)!=FILE_TAG) panic("%x is not a file handle",f);
#endif
*((dword*)f)-2)=BLOC_TAG;
kfree(f);
}
Re:debugging interface
Pype's post has reminded me of another debugging aid: checked mallocs and frees. Bad pointer writes happen less than null pointer accesses, but when they do, they often happen close to some valid memory. So you can write a layer on top of malloc and free which checks blocks.
Here's my maldebug.c:
Here's my maldebug.c:
Code: Select all
/* $Id: maldebug.c,v 1.1.1.1 2002/12/21 09:50:10 pavlovskii Exp $ */
#include <malloc.h>
#include <string.h>
#include <wchar.h>
#include <stdio.h>
#undef malloc
#undef free
#undef realloc
static __maldbg_header_t *maldbg_first, *maldbg_last;
static int maldbg_tag;
#define MAL_MAGIC 0xdeadbeef
void *__malloc(size_t size, const char *file, int line)
{
__maldbg_header_t *header;
header = malloc(sizeof(__maldbg_header_t) + size);
if (header == NULL)
return NULL;
header->line = line;
header->file = file;
header->prev = maldbg_last;
header->size = sizeof(__maldbg_header_t) + size;
header->tag = maldbg_tag;
header->magic[0] = MAL_MAGIC;
header->magic[1] = line ^ header->magic[0];
header->next = NULL;
if (maldbg_last != NULL)
maldbg_last->next = header;
if (maldbg_first == NULL)
maldbg_first = header;
maldbg_last = header;
return header + 1;
}
void __free(void *ptr, const char *file, int line)
{
__maldbg_header_t *header;
if (ptr != NULL)
{
header = (__maldbg_header_t*) ptr - 1;
if (header->prev != NULL)
header->prev->next = header->next;
if (header->next != NULL)
header->next->prev = header->prev;
if (maldbg_last == header)
maldbg_last = header->prev;
if (maldbg_first == header)
maldbg_first = header->next;
header->tag = 0;
free(header);
}
}
void *__realloc(void *ptr, size_t size, const char *file, int line)
{
__maldbg_header_t *header;
if (ptr == NULL)
return __malloc(size, file, line);
else
{
header = (__maldbg_header_t*) ptr - 1;
header = realloc(header, sizeof(__maldbg_header_t) + size);
if (header->next == NULL)
maldbg_last = header;
else
header->next->prev = header;
if (header->prev == NULL)
maldbg_first = header;
else
header->prev->next = header;
header->size = sizeof(__maldbg_header_t) + size;
return header + 1;
}
}
wchar_t *__wcsdup(const wchar_t* str, const char *file, int line)
{
wchar_t *ret;
if (str == NULL)
str = L"";
ret = __malloc((wcslen(str) + 1) * sizeof(wchar_t), file, line);
if (!ret)
return NULL;
wcscpy(ret, str);
return ret;
}
void __malloc_leak(int tag)
{
maldbg_tag = tag;
}
bool __malloc_check_header(__maldbg_header_t *header)
{
if (header->magic[0] != 0xdeadbeef)
{
wprintf(L"%p: memory check error (1): got 0x%x, should be 0xdeadbeef\n",
header + 1, header->magic[0]);
return false;
}
if (header->magic[1] != (header->magic[0] ^ header->line))
{
wprintf(L"%p: memory check error (2): got 0x%x, should be 0x%x\n",
header + 1, header->magic[1], header->magic[0] ^ header->line);
return false;
}
return true;
}
void __malloc_leak_dump(void)
{
__maldbg_header_t *header;
for (header = maldbg_first; header != NULL; header = header->next)
if (__malloc_check_header(header) &&
header->tag == maldbg_tag)
wprintf(L"%S(%d): memory leaked: %p\n",
header->file, header->line, header + 1);
}
__maldbg_header_t *__malloc_find_block(void *addr)
{
__maldbg_header_t *header;
for (header = maldbg_first; header != NULL; header = header->next)
if ((__maldbg_header_t*) addr >= header &&
__malloc_check_header(header) &&
(uint8_t*) addr < (uint8_t*) header + header->size)
return header;
return NULL;
}
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:debugging interface
hehe 0xdeadbeef is at it againTim Robinson wrote: Pype's post has reminded me of another debugging aid: checked mallocs and frees.
you really store the file name and line number for the allocation of every block !? whoaw!. i never ever dared to push debugging *that* far .
note that it roughly provide the same kind of information as my tags do if i have only one constructor per tag
Re:debugging interface
It's only two pointers per block, and it's a pretty good way to identify a particular malloced block. Note also the leak dumping. It would be nice to have a stack dump for every block, but that might be taking things too far (although I believe Boundschecker gives you this).