📄 thread-packets.c
字号:
//========================================================================
//
// thread-packets.c
//
// Provides multi-threaded debug support
//
//========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): Red Hat, nickg
// Contributors: Red Hat, nickg
// Date: 1998-08-25
// Purpose:
// Description: Provides multi-threaded debug support
// Usage:
//
//####DESCRIPTIONEND####
//
//========================================================================
// Define __ECOS__; allows all eCos specific additions to be easily identified.
#define __ECOS__
// #ifdef __ECOS__
#include <pkgconf/hal.h>
#if defined(CYGDBG_HAL_DEBUG_GDB_THREAD_SUPPORT) \ && defined(CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS)
// #endif // __ECOS__
/* FIXME: Scan this module for correct sizes of fields in packets */
#ifdef __ECOS__
#include <cyg/hal/dbg-threads-api.h>
#else // __ECOS__
#include "dbg-threads-api.h"
#endif // __ECOS__
/* This file should ALWAYS define debug thread support */
/* Dont include the object in the link if you dont need the support */
/* This is NOT the internal unit debug flag, it is a feature control */
#if defined(DEBUG_THREADS)
#undef DEBUG_THREADS
#endif
#define DEBUG_THREADS 1
#define UNIT_TEST 0
#define GDB_MOCKUP 0
#define STUB_BUF_MAX 300 /* for range checking of packet lengths */
#include "thread-pkts.h"
#ifdef __ECOS__
// Use HAL rather than board.h in eCos
#include <cyg/hal/hal_stub.h>
#else // __ECOS__
#include "board.h"
#endif // __ECOS__
/*
* Export the continue and "general" (context) thread IDs from GDB.
*/
int _gdb_cont_thread ;
int _gdb_general_thread ;
#if !defined(PKT_DEBUG)
#define PKT_DEBUG 0
#endif
extern void output_string(char * message) ;
#if PKT_DEBUG
void output_threadid(char * title,threadref * ref) ;
#warning "PKT_DEBUG macros engaged"
#define PKT_TRACE(title,packet) \{ output_string(title) ; output_string(packet) ; output_string("\n") ;}
#else
#define PKT_TRACE(title,packet) {}
#endif
/* This is going to be irregular because the various implementations
have adopted different names for registers.
It would be nice to fix them to have a common convention
_stub_registers
stub_registers
alt_stub_registers
*/
extern target_register_t * _registers ;
/* A pointer to the current set of registers */
extern target_register_t registers[]; /* The current saved registers */
extern target_register_t alt_registers[] ;
/* Thread or saved process state */
static void stub_copy_registers(
target_register_t * dest,
target_register_t *src
)
{
target_register_t * limit ;
limit = dest + NUMREGS ;
while (dest < limit) *dest++ = *src++ ;
}
#ifdef __ECOS__
void __stub_copy_registers(target_register_t * dest,
target_register_t *src)
{
stub_copy_registers(dest, src);
}
#endif // __ECOS__
extern int stubhex(char ch) ;
/* ----- STUB_PACK_NAK ----------------------------------- */
/* Pack an error response into the response packet */
char * stub_pack_nak(char * outbuf)
{
*outbuf++ = 'E' ;
*outbuf++ = '0' ;
*outbuf++ = '2' ;
return outbuf ;
} /* stub_pack_nak */
/* ----- STUB_PACK_ACK -------------------------- */
/* Pack an OK achnowledgement */
char * stub_pack_ack(char * outbuf)
{
*outbuf++ = 'O' ;
*outbuf++ = 'K' ;
return outbuf ;
} /* stub_pack_ack */
/* ------- STUB_UNPACK_INT ------------------------------- */
/* Unpack a few bytes and return its integer value */
/* This is where I wish functions could return several values
I would also advance the buffer pointer */
int stub_unpack_int(char * buff,int fieldlength)
{
int retval = 0 ;
int nibble ;
while (fieldlength)
{ nibble = stubhex(*buff++) ;
retval |= nibble ;
fieldlength-- ;
if (fieldlength) retval = retval << 4 ;
}
return retval ;
} /* stub_unpack_int */
static char * unpack_byte(char * buf, int * value)
{
*value = stub_unpack_int(buf,2) ;
return buf + 2 ;
}
static char * unpack_int(char * buf, int * value)
{
*value = stub_unpack_int(buf,8) ;
return buf + 8 ;
}
/* We are NOT depending upon extensive libraries */
static int ishex(char ch,int *val)
{
if ((ch >= 'a') && (ch <= 'f'))
{ *val =ch - 'a' + 10 ; return 1 ; }
if ((ch >= 'A') && (ch <= 'F'))
{ *val = ch - 'A' + 10 ; return 1 ;}
if ((ch >= '0') && (ch <= '9'))
{ *val = ch - '0' ; return 1 ; }
return 0 ;
} /* ishex */
static char * unpack_nibble(char * buf,int * val)
{
ishex(*buf++,val) ;
return buf ;
}
static const char hexchars[] = "0123456789abcdef";
static char * pack_hex_byte(char * pkt, unsigned char byte)
{
*pkt++ = hexchars[(byte >> 4) & 0xf] ;
*pkt++ = hexchars[(byte & 0xf)] ;
return pkt ;
} /* pack_hex_byte */
#ifndef __ECOS__
/* ---- STUB_PACK_VARLEN_HEX ------------------------------------- */
/* Format a variable length stream of hex bytes */
static char * pack_varlen_hex(
char * pkt,
unsigned int value)
{
int i ;
static unsigned char n[8] ;
if (value == 0)
{
*pkt++ = '0' ;
return pkt ;
}
else
{
i = 8 ;
while (i-- >= 0 ) /* unpack nibbles into a char array */
{
n[i] = value & 0x0f ;
value = value >> 4 ;
}
i = 0 ; /* we had decrmented it to -1 */
while (n[i] == 0 ) i++ ; /* drop leading zeroes */
while (i++ < 8) *pkt++ = hexchars[n[i]] ; /* pack the number */
}
return pkt ;
} /* pack_varlen_hex */
#endif // !__ECOS__
/* ------ STUB_UNPACK_VARLEN_HEX -------------------------------- */
/* Parse a stream of hex bytes which may be of variable length */
/* return the pointer to the next char */
/* modify a varparm containing the result */
/* A failure would look like a non-increment of the buffer pointer */
/* This unpacks hex strings that may have been packed using sprintf(%x) */
/* We assume some non-hex delimits them */
char * unpack_varlen_hex(
char * buff, /* packet to parse */
int * result)
{
int nibble ;
int retval ;
retval = 0 ;
while (ishex(*buff,&nibble))
{
buff++ ;
retval = retval << 4 ;
retval |= nibble & 0x0f ;
}
*result = retval ;
return buff ;
} /* stub_unpack_varlen_int */
/* ------ UNPACK_THREADID ------------------------------- */
/* A threadid is a 64 bit quantity */
#define BUFTHREADIDSIZ 16 /* encode 64 bits in 16 chars of hex */
static char * unpack_threadid(char * inbuf, threadref * id)
{
char * altref ;
char * limit = inbuf + BUFTHREADIDSIZ ;
int x,y ;
altref = (char *) id ;
while (inbuf < limit)
{
x = stubhex(*inbuf++) ;
y = stubhex(*inbuf++) ;
*altref++ = (x << 4) | y ;
}
return inbuf ;
} /* unpack_threadid */
/* Pack an integer use leading zeroes */
static char * pack_int(char * buf,int value)
{
buf = pack_hex_byte(buf,(value>> 24)& 0xff) ;
buf = pack_hex_byte(buf,(value >>16)& 0xff) ;
buf = pack_hex_byte(buf,(value >>8) & 0x0ff) ;
buf = pack_hex_byte(buf,(value & 0xff)) ;
return buf ;
} /* pack_int */
/* -------- PACK_STRING ---------------------------------------------- */
/* This stupid string better not contain any funny characters */
/* Also, the GDB protocol will not cope with NULLs in the
string or at the end of it.
While is is posable to encapsulate the protocol in ays that
preclude filtering for # I am assuming this is a constraint.
*/
static char * pack_raw_string(char * pkt,char * string)
{
char ch ;
while (0 != (ch = *string++)) *pkt++ = ch ;
return pkt ;
}
static char * pack_string(
char * pkt,
char * string)
{
char ch ;
#ifdef __ECOS__
int len = 0;
char *s = string;
while( *s++ ) len++;
#else // __ECOS__
int len ;
len = strlen(string) ;
#endif // __ECOS
if (len > 200 ) len = 200 ; /* Bigger than most GDB packets, junk??? */
pkt = pack_hex_byte(pkt,len) ;
while (len-- > 0)
{
ch = *string++ ;
if ((ch == '\0') || (ch == '#')) ch = '*' ; /* Protect encapsulation */
*pkt++ = ch ;
}
return pkt ;
} /* pack_string */
/* ----- STUB_PACK_THREADID --------------------------------------------- */
/* Convert a binary 64 bit threadid and pack it into a xmit buffer */
/* Return the advanced buffer pointer */
static char * pack_threadid(char * pkt, threadref * id)
{
char * limit ;
unsigned char * altid ;
altid = (unsigned char *) id ;
limit = pkt + BUFTHREADIDSIZ ;
while (pkt < limit) pkt = pack_hex_byte(pkt,*altid++) ;
return pkt ;
} /* stub_pack_threadid */
/* UNFORTUNATELY, not all of the extended debugging system has yet been
converted to 64 but thread references and process identifiers.
These routines do the conversion.
An array of bytes is the correct treatment of an opaque identifier.
ints have endian issues.
*/
static void int_to_threadref(threadref * id, int value)
{
unsigned char * scan ;
scan = (unsigned char *) id ;
{
int i = 4 ;
while (i--) *scan++ = 0 ;
}
*scan++ = (value >> 24) & 0xff ;
*scan++ = (value >> 16) & 0xff ;
*scan++ = (value >> 8) & 0xff ;
*scan++ = (value & 0xff) ;
}
static int threadref_to_int(threadref * ref)
{
int value = 0 ;
unsigned char * scan ;
int i ;
scan = (char *) ref ;
scan += 4 ;
i = 4 ;
while (i-- > 0) value = (value << 8) | ((*scan++) & 0xff) ;
return value ;
} /* threadref_to_int */
void copy_threadref(threadref * dest, threadref * src)
{
int i ;
unsigned char * csrc, * cdest ;
csrc = (unsigned char *) src ;
cdest = (unsigned char *) dest ;
i = 8 ;
while (i--) *cdest++ = *csrc++ ;
}
int threadmatch(
threadref * dest ,
threadref * src
)
{
unsigned char * srcp, * destp ;
int i , result ;
srcp = (char *) src ;
destp = (char *) dest ;
i = 8 ;
result = 1 ;
while (i-- > 0 ) result &= (*srcp++ == *destp++) ? 1 : 0 ;
return result ;
} /* threadmatch */
static char * Tpkt_threadtag = "thread:" ;
/* ----- STUB_PACK_TPKT_THREADID ------------------------------------ */
/* retreive, tag and insert a thread identifier into a T packet. */
/* Insert nothing if the thread identifier is not available */
char * stub_pack_Tpkt_threadid(char * pkt)
{
static threadref thread ;
int fmt = 0 ; /* old format */
PKT_TRACE("Tpkt-id","---") ;
if (dbg_currthread(&thread))
{
pkt = pack_raw_string(pkt,Tpkt_threadtag) ;
if (fmt)
pkt = pack_threadid(pkt,&thread) ;
else
/* Until GDB lengthens its thread ids, we have to MASH
the threadid into somthing shorter. PLEASE FIX GDB */
pkt = pack_int(pkt,threadref_to_int(&thread)) ;
*pkt++ = ';' ; /* terminate variable length int */
*pkt = '\0' ; /* Null terminate to allow string to be printed, no++ */
}
PKT_TRACE("packedTpkt","--") ;
return pkt ;
} /* stub_pack_Tpkt_threadid */
long stub_get_currthread (void)
{
threadref thread ;
if (dbg_currthread(&thread))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -