📄 rtems-stub-glue.c
字号:
/* * This file contains the RTEMS thread awareness support for GDB stubs. * * This file is derived from an RTEMS thread aware i386-stub.c that * had the following copyright announcements: * * This software is Copyright (C) 1998 by T.sqware - all rights limited * It is provided in to the public domain "as is", can be freely modified * as far as this copyight notice is kept unchanged, but does not imply * an endorsement by T.sqware of the product in which it is included. * * * Modifications for RTEMS threads and more * * Copyright (C) 2000 Quality Quorum, Inc. * * All Rights Reserved * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted. * * QQI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL * QQI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */#include <rtems.h>#include <string.h>#include "gdb_if.h"/* Change it to something meaningful when debugging */#undef ASSERT#define ASSERT(x) extern const char gdb_hexchars[];/* * Prototypes for CPU dependent routines that are conditional * at the bottom of this file. */void rtems_gdb_stub_get_registers_from_context( int *registers, Thread_Control *th);/* Check whether it is OK to enable thread support */int rtems_gdb_stub_thread_support_ok(void){ if (_System_state_Get() == SYSTEM_STATE_UP) { return 1; } return 0;}/* * rtems_gdb_stub_id_to_index * * Return the gdb thread id for the specified RTEMS thread id */int rtems_gdb_stub_id_to_index( Objects_Id thread_obj_id){ Objects_Id min_id, max_id; int first_posix_id, first_rtems_id; Objects_Information *obj_info; if (_System_state_Get() != SYSTEM_STATE_UP) { /* We have one thread let us use value reserved for idle thread */ return 1; } if (_Thread_Executing == _Thread_Idle) { return 1; } /* Let us figure out thread_id for gdb */ first_rtems_id = 2; obj_info = _Objects_Information_table[OBJECTS_CLASSIC_API][1]; min_id = obj_info->minimum_id; max_id = obj_info->maximum_id; if (thread_obj_id >= min_id && thread_obj_id < max_id) { return first_rtems_id + (thread_obj_id - min_id); } first_posix_id = first_rtems_id + (max_id - min_id) + 1; min_id = _Objects_Information_table[OBJECTS_POSIX_API][1]->minimum_id; return first_posix_id + (thread_obj_id - min_id);} /* Return the RTEMS thread id from a gdb thread id */Thread_Control *rtems_gdb_index_to_stub_id( int thread){ Objects_Id thread_obj_id; Objects_Id min_id, max_id; int first_posix_id, first_rtems_id; Objects_Information *obj_info; Thread_Control *th; ASSERT(registers != NULL); if (_System_state_Get() != SYSTEM_STATE_UP || thread <= 0) { /* Should not happen */ return NULL; } if (thread == 1) { th = _Thread_Idle; goto found; } /* Let us get object associtated with current thread */ first_rtems_id = 2; thread_obj_id = _Thread_Executing->Object.id; /* Let us figure out thread_id for gdb */ obj_info = _Objects_Information_table[OBJECTS_CLASSIC_API][1]; min_id = obj_info->minimum_id; max_id = obj_info->maximum_id; if (thread <= (first_rtems_id + (max_id - min_id))) { th = (Thread_Control *)(obj_info->local_table[thread - first_rtems_id + 1]); if (th != NULL) { goto found; } /* Thread does not exist */ return NULL; } first_posix_id = first_rtems_id + (max_id - min_id) + 1; obj_info = _Objects_Information_table[OBJECTS_POSIX_API][1]; min_id = obj_info->minimum_id; max_id = obj_info->maximum_id; th = (Thread_Control *)(obj_info->local_table[thread - first_posix_id + 1]); if (th == NULL) { /* Thread does not exist */ return NULL; } found: return th;}/* Get id of the thread stopped by exception */int rtems_gdb_stub_get_current_thread(void){ return rtems_gdb_stub_id_to_index( _Thread_Executing->Object.id );}/* Get id of the next thread after athread, if argument <= 0 find the first available thread, return thread if found or 0 if not */int rtems_gdb_stub_get_next_thread(int athread){ Objects_Id id, min_id, max_id; int lim, first_posix_id, first_rtems_id; Objects_Information *obj_info; int start; if (_System_state_Get() != SYSTEM_STATE_UP) { /* We have one thread let us use value of idle thread */ return (athread < 1) ? 1 : 0; } if (athread < 1) { return 1; } first_rtems_id = 2; obj_info = _Objects_Information_table[OBJECTS_CLASSIC_API][1]; min_id = obj_info->minimum_id; max_id = obj_info->maximum_id; lim = first_rtems_id + max_id - min_id; if (athread < lim) { if (athread < first_rtems_id) { start = first_rtems_id; } else { start = 1 + athread; } for (id=start; id<=lim; id++) { if (obj_info->local_table[id - first_rtems_id + 1] != NULL) { return id; } } } first_posix_id = first_rtems_id + (max_id - min_id) + 1; obj_info = _Objects_Information_table[OBJECTS_POSIX_API][1]; min_id = obj_info->minimum_id; max_id = obj_info->maximum_id; lim = first_posix_id + (max_id - min_id); if (athread < lim) { if (athread < first_posix_id) { start = first_posix_id; } else { start = 1 + athread; } for (id=start; id<=lim; id++) { if (obj_info->local_table[id - first_posix_id + 1] != NULL) { return id; } } } /* Not found */ return 0;}/* Get thread registers, return 0 if thread does not exist, and 1 otherwise */int rtems_gdb_stub_get_thread_regs( int thread, unsigned int *registers){ Thread_Control *th; th= rtems_gdb_index_to_stub_id(thread); if( th ) { rtems_gdb_stub_get_registers_from_context( registers, th ); return 1; } return 0;}/* Set thread registers, return 0 if thread does not exist or register values will screw up the threads, and 1 otherwise */int rtems_gdb_stub_set_thread_regs( int thread, unsigned int *registers){ /* In current situation there is no point in changing any registers here thread status is displayed as being deep inside thread switching and we better do not screw up anything there - it may be fixed eventually though */ return 1;}/* Get thread information, return 0 if thread does not exist and 1 otherwise */int rtems_gdb_stub_get_thread_info( int thread, struct rtems_gdb_stub_thread_info *info){ Objects_Id thread_obj_id; Objects_Id min_id, max_id; int first_posix_id, first_rtems_id; Objects_Information *obj_info; Thread_Control *th; unsigned32 name; char tmp_buf[20]; ASSERT(info != NULL); if (thread <= 0) { return 0; } if (_System_state_Get() != SYSTEM_STATE_UP || thread == 1) { /* We have one thread let us use value which will never happen for real thread */ strcpy(info->display, "idle thread"); strcpy(info->name, "IDLE"); info->more_display[0] = 0; /* Nothing */ return 1; } /* Let us get object associtated with current thread */ thread_obj_id = _Thread_Executing->Object.id; /* Let us figure out thread_id for gdb */ first_rtems_id = 2; obj_info = _Objects_Information_table[OBJECTS_CLASSIC_API][1]; min_id = obj_info->minimum_id; max_id = obj_info->maximum_id; if (thread <= (first_rtems_id + (max_id - min_id))) { th = (Thread_Control *)(obj_info->local_table[thread - first_rtems_id + 1]); if (th == NULL) { /* Thread does not exist */ return 0; } strcpy(info->display, "rtems task: control at 0x"); tmp_buf[0] = gdb_hexchars[(((int)th) >> 28) & 0xf]; tmp_buf[1] = gdb_hexchars[(((int)th) >> 24) & 0xf]; tmp_buf[2] = gdb_hexchars[(((int)th) >> 20) & 0xf]; tmp_buf[3] = gdb_hexchars[(((int)th) >> 16) & 0xf]; tmp_buf[4] = gdb_hexchars[(((int)th) >> 12) & 0xf]; tmp_buf[5] = gdb_hexchars[(((int)th) >> 8) & 0xf]; tmp_buf[6] = gdb_hexchars[(((int)th) >> 4) & 0xf]; tmp_buf[7] = gdb_hexchars[((int)th) & 0xf]; tmp_buf[8] = 0; strcat(info->display, tmp_buf);#if 0 name = *(unsigned32 *)(obj_info->local_table[thread]->name);#else name = *(unsigned32 *)(obj_info->local_table[thread - first_rtems_id + 1]->name);#endif info->name[0] = (name >> 24) & 0xff; info->name[1] = (name >> 16) & 0xff; info->name[2] = (name >> 8) & 0xff; info->name[3] = name & 0xff; info->name[4] = 0; info->more_display[0] = 0; /* Nothing */ return 1; } first_posix_id = first_rtems_id + (max_id - min_id) + 1; obj_info = _Objects_Information_table[OBJECTS_POSIX_API][1]; min_id = obj_info->minimum_id; max_id = obj_info->maximum_id; th = (Thread_Control *)(obj_info->local_table[thread - first_posix_id + 1]); if (th == NULL) { /* Thread does not exist */ return 0; } strcpy(info->display, "posix thread: control at 0x"); tmp_buf[0] = gdb_hexchars[(((int)th) >> 28) & 0xf]; tmp_buf[1] = gdb_hexchars[(((int)th) >> 24) & 0xf]; tmp_buf[2] = gdb_hexchars[(((int)th) >> 20) & 0xf]; tmp_buf[3] = gdb_hexchars[(((int)th) >> 16) & 0xf]; tmp_buf[4] = gdb_hexchars[(((int)th) >> 12) & 0xf]; tmp_buf[5] = gdb_hexchars[(((int)th) >> 8) & 0xf]; tmp_buf[6] = gdb_hexchars[(((int)th) >> 4) & 0xf]; tmp_buf[7] = gdb_hexchars[((int)th) & 0xf]; tmp_buf[8] = 0; strcat(info->display, tmp_buf); name = *(unsigned32 *)(obj_info->local_table[thread - first_posix_id + 1]->name); info->name[0] = (name >> 24) & 0xff; info->name[1] = (name >> 16) & 0xff; info->name[2] = (name >> 8) & 0xff; info->name[3] = name & 0xff; info->name[4] = 0; info->more_display[0] = 0; /* Nothing */ return 1;}/*******************************************************//* Format: x<type-1x>,<address-x>,<length-x>, where x is 'z' or 'Z' */int parse_zbreak(const char *in, int *type, unsigned char **addr, int *len){ int ttmp, atmp, ltmp; ASSERT(in != NULL); ASSERT(type != NULL); ASSERT(addr != NULL); ASSERT(len != NULL); ASSERT(*in == 'z' || *in == 'Z'); in++; if (!hstr2nibble(in, &ttmp) || *(in+1) != ',') { return 0; } in += 2; in = vhstr2int(in, &atmp); if (in == NULL || *in != ',') { return 0; } in++; in = vhstr2int(in, <mp); if (in == NULL || ltmp < 1) { return 0; } *type = ttmp; *addr = (unsigned char *)atmp; *len = ltmp; return 1;}/* Format: qP<mask-08x><thread_id-ft> */static intparse_qp(const char *in, int *mask, int *thread){ const char *ptr; ASSERT(in != NULL); ASSERT(*in == 'q'); ASSERT(*(in+1) == 'P'); ptr = fhstr2int(in+2, mask); if (ptr == NULL) { return 0; } ptr = fhstr2thread(ptr, thread); if (ptr == NULL) { return 0; } return 1;}/* Format: qQ<mask-08x><thread_id-ft><tag-08x><length-02x><value>...] */static voidpack_qq(char *out, int mask, int thread, struct rtems_gdb_stub_thread_info *info){ int len; ASSERT(out != NULL); ASSERT(info != NULL); *out++ = 'q'; *out++ = 'Q'; out = int2fhstr(out, mask); out = thread2fhstr(out, thread); if (mask & 0x1) { /* Thread id once again */ memcpy(out, "00000001", 8); out += 8; *out++ = '1'; *out++ = '0'; out = thread2fhstr(out, thread); } if (mask & 0x2) { /* Exists */ memcpy(out, "00000002", 8); out += 8; *out++ = '0'; *out++ = '1'; *out++ = '1'; } if (mask & 0x4) { /* Display */ memcpy(out, "00000004", 8); out += 8; info->display[sizeof(info->display)-1] = 0; /* Fot God sake */ len = strlen(info->display); *out++ = gdb_hexchars[len >> 4]; *out++ = gdb_hexchars[len & 0x0f]; memcpy(out, info->display, len); out += len; } if (mask & 0x8) { /* Name */ memcpy(out, "00000008", 8); out += 8; info->name[sizeof(info->name)-1] = 0; /* Fot God sake */ len = strlen(info->name); *out++ = gdb_hexchars[len >> 4]; *out++ = gdb_hexchars[len & 0x0f]; memcpy(out, info->name, len); out += len; } if (mask & 0x10) { /* More display */ memcpy(out, "00000010", 8); out += 8; info->more_display[sizeof(info->more_display)-1] = 0; /* Fot God sake */ len = strlen(info->more_display); *out++ = gdb_hexchars[len >> 4]; *out++ = gdb_hexchars[len & 0x0f]; memcpy(out, info->more_display, len); out += len; } *out = 0; return;}/* Format qL<first-01x><max_count-02x><arg_thread_id-ft> */static intparse_ql(const char *in, int *first, int *max_count, int *athread){ const char *ptr; ASSERT(in != NULL); ASSERT(*in == 'q'); ASSERT(*(in+1) == 'L'); ASSERT(first != NULL); ASSERT(max_count != NULL); ASSERT(athread != NULL); ptr = in + 2; /* First */ if (!hstr2nibble(ptr, first)) { return 0; } ptr++; /* Max count */ if (!hstr2byte(ptr, max_count)) { return 0; } ptr += 2; /* A thread */ ptr = fhstr2thread(ptr, athread); if (ptr == NULL) { return 0; } return 1;}/* Format: qM<count-02x><done-01x><arg_thread_id>[<found_thread_id-ft>...] */static char *reserve_qm_header(char *out){ ASSERT(out != NULL); return out + 21;}/* Format: qM<count-02x><done-01x><arg_thread_id>[<found_thread_id-ft>...] */static char*pack_qm_thread(char *out, int thread){ ASSERT(out != 0); return thread2fhstr(out, thread);}/* Format: qM<count-02x><done-01x><arg_thread_id>[<found_thread_id-ft>...] */static voidpack_qm_header(char *out, int count, int done, int athread){ ASSERT(out != 0); ASSERT(count >= 0 && count < 256); *out++ = 'q'; *out++ = 'M'; *out++ = gdb_hexchars[(count >> 4) & 0x0f]; *out++ = gdb_hexchars[count & 0x0f]; if (done) { *out++ = '1'; } else { *out++ = '0'; } thread2fhstr(out, athread); return;}void rtems_gdb_process_query( char *inbuffer, char *outbuffer, int do_threads, int thread){ char *optr; switch(inbuffer[1]) { case 'C': /* Current thread query query - return stopped thread */ if (!do_threads) { break; } optr = outbuffer; *optr++ = 'Q'; *optr++ = 'C'; optr = thread2vhstr(optr, thread); *optr = 0; break; case 'P': /* Thread info query */ if (!do_threads) { break; } { int ret, rthread, mask; struct rtems_gdb_stub_thread_info info; ret = parse_qp(inbuffer, &mask, &rthread); if (!ret|| mask & ~0x1f) { strcpy(outbuffer, "E01"); break; } ret = rtems_gdb_stub_get_thread_info(rthread, &info); if (!ret) { /* Good implementation would never ask for non-existing thread, should we care about bad ones - it does not seem so */ strcpy(outbuffer, "E02"); break; } /* Build response */ pack_qq(outbuffer, mask, rthread, &info); } break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -