You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

435 lines
13 KiB

  1. /***************************************************************************
  2. * *
  3. * This program is free software; you can redistribute it and/or modify *
  4. * it under the terms of the GNU General Public License as published by *
  5. * the Free Software Foundation; either version 2 of the License, or *
  6. * (at your option) any later version. *
  7. * *
  8. * This program is distributed in the hope that it will be useful, *
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  11. * GNU General Public License for more details. *
  12. * *
  13. * You should have received a copy of the GNU General Public License *
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>. *
  15. ***************************************************************************/
  16. #ifdef HAVE_CONFIG_H
  17. #include "config.h"
  18. #endif
  19. #include <helper/time_support.h>
  20. #include <jtag/jtag.h>
  21. #include "target/target.h"
  22. #include "target/target_type.h"
  23. #include "target/register.h"
  24. #include "rtos.h"
  25. #include "helper/log.h"
  26. #include "helper/types.h"
  27. #include "server/gdb_server.h"
  28. static bool hwthread_detect_rtos(struct target *target);
  29. static int hwthread_create(struct target *target);
  30. static int hwthread_update_threads(struct rtos *rtos);
  31. static int hwthread_get_thread_reg(struct rtos *rtos, int64_t thread_id,
  32. uint32_t reg_num, struct rtos_reg *rtos_reg);
  33. static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
  34. struct rtos_reg **reg_list, int *num_regs);
  35. static int hwthread_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]);
  36. static int hwthread_smp_init(struct target *target);
  37. static int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value);
  38. static int hwthread_read_buffer(struct rtos *rtos, target_addr_t address,
  39. uint32_t size, uint8_t *buffer);
  40. static int hwthread_write_buffer(struct rtos *rtos, target_addr_t address,
  41. uint32_t size, const uint8_t *buffer);
  42. #define HW_THREAD_NAME_STR_SIZE (32)
  43. extern int rtos_thread_packet(struct connection *connection, const char *packet, int packet_size);
  44. static inline threadid_t threadid_from_target(const struct target *target)
  45. {
  46. return target->coreid + 1;
  47. }
  48. const struct rtos_type hwthread_rtos = {
  49. .name = "hwthread",
  50. .detect_rtos = hwthread_detect_rtos,
  51. .create = hwthread_create,
  52. .update_threads = hwthread_update_threads,
  53. .get_thread_reg_list = hwthread_get_thread_reg_list,
  54. .get_thread_reg = hwthread_get_thread_reg,
  55. .get_symbol_list_to_lookup = hwthread_get_symbol_list_to_lookup,
  56. .smp_init = hwthread_smp_init,
  57. .set_reg = hwthread_set_reg,
  58. .read_buffer = hwthread_read_buffer,
  59. .write_buffer = hwthread_write_buffer,
  60. };
  61. struct hwthread_params {
  62. int dummy_param;
  63. };
  64. static int hwthread_fill_thread(struct rtos *rtos, struct target *curr, int thread_num)
  65. {
  66. char tmp_str[HW_THREAD_NAME_STR_SIZE];
  67. threadid_t tid = threadid_from_target(curr);
  68. memset(tmp_str, 0, HW_THREAD_NAME_STR_SIZE);
  69. /* thread-id is the core-id of this core inside the SMP group plus 1 */
  70. rtos->thread_details[thread_num].threadid = tid;
  71. /* create the thread name */
  72. rtos->thread_details[thread_num].exists = true;
  73. rtos->thread_details[thread_num].thread_name_str = strdup(target_name(curr));
  74. snprintf(tmp_str, HW_THREAD_NAME_STR_SIZE-1, "state: %s", debug_reason_name(curr));
  75. rtos->thread_details[thread_num].extra_info_str = strdup(tmp_str);
  76. return ERROR_OK;
  77. }
  78. static int hwthread_update_threads(struct rtos *rtos)
  79. {
  80. int threads_found = 0;
  81. int thread_list_size = 0;
  82. struct target_list *head;
  83. struct target *target;
  84. int64_t current_thread = 0;
  85. enum target_debug_reason current_reason = DBG_REASON_UNDEFINED;
  86. if (!rtos)
  87. return -1;
  88. target = rtos->target;
  89. /* wipe out previous thread details if any */
  90. rtos_free_threadlist(rtos);
  91. /* determine the number of "threads" */
  92. if (target->smp) {
  93. for (head = target->head; head; head = head->next) {
  94. struct target *curr = head->target;
  95. if (!target_was_examined(curr))
  96. continue;
  97. ++thread_list_size;
  98. }
  99. } else
  100. thread_list_size = 1;
  101. /* create space for new thread details */
  102. rtos->thread_details = malloc(sizeof(struct thread_detail) * thread_list_size);
  103. if (target->smp) {
  104. /* loop over all threads */
  105. for (head = target->head; head; head = head->next) {
  106. struct target *curr = head->target;
  107. if (!target_was_examined(curr))
  108. continue;
  109. threadid_t tid = threadid_from_target(curr);
  110. hwthread_fill_thread(rtos, curr, threads_found);
  111. /* find an interesting thread to set as current */
  112. switch (current_reason) {
  113. case DBG_REASON_UNDEFINED:
  114. current_reason = curr->debug_reason;
  115. current_thread = tid;
  116. break;
  117. case DBG_REASON_SINGLESTEP:
  118. /* single-step can only be overridden by itself */
  119. if (curr->debug_reason == DBG_REASON_SINGLESTEP) {
  120. if (tid == rtos->current_threadid)
  121. current_thread = tid;
  122. }
  123. break;
  124. case DBG_REASON_BREAKPOINT:
  125. /* single-step overrides breakpoint */
  126. if (curr->debug_reason == DBG_REASON_SINGLESTEP) {
  127. current_reason = curr->debug_reason;
  128. current_thread = tid;
  129. } else
  130. /* multiple breakpoints, prefer gdbs' threadid */
  131. if (curr->debug_reason == DBG_REASON_BREAKPOINT) {
  132. if (tid == rtos->current_threadid)
  133. current_thread = tid;
  134. }
  135. break;
  136. case DBG_REASON_WATCHPOINT:
  137. /* breakpoint and single-step override watchpoint */
  138. if (curr->debug_reason == DBG_REASON_SINGLESTEP ||
  139. curr->debug_reason == DBG_REASON_BREAKPOINT) {
  140. current_reason = curr->debug_reason;
  141. current_thread = tid;
  142. }
  143. break;
  144. case DBG_REASON_DBGRQ:
  145. /* all other reasons override debug-request */
  146. if (curr->debug_reason == DBG_REASON_SINGLESTEP ||
  147. curr->debug_reason == DBG_REASON_WATCHPOINT ||
  148. curr->debug_reason == DBG_REASON_BREAKPOINT) {
  149. current_reason = curr->debug_reason;
  150. current_thread = tid;
  151. } else
  152. if (curr->debug_reason == DBG_REASON_DBGRQ) {
  153. if (tid == rtos->current_threadid)
  154. current_thread = tid;
  155. }
  156. break;
  157. default:
  158. break;
  159. }
  160. threads_found++;
  161. }
  162. } else {
  163. hwthread_fill_thread(rtos, target, threads_found);
  164. current_thread = threadid_from_target(target);
  165. threads_found++;
  166. }
  167. rtos->thread_count = threads_found;
  168. /* we found an interesting thread, set it as current */
  169. if (current_thread != 0)
  170. rtos->current_thread = current_thread;
  171. else if (rtos->current_threadid != 0)
  172. rtos->current_thread = rtos->current_threadid;
  173. else
  174. rtos->current_thread = threadid_from_target(target);
  175. LOG_DEBUG("%s current_thread=%i", __func__, (int)rtos->current_thread);
  176. return 0;
  177. }
  178. static int hwthread_smp_init(struct target *target)
  179. {
  180. return hwthread_update_threads(target->rtos);
  181. }
  182. static struct target *hwthread_find_thread(struct target *target, int64_t thread_id)
  183. {
  184. /* Find the thread with that thread_id */
  185. if (!target)
  186. return NULL;
  187. if (target->smp) {
  188. for (struct target_list *head = target->head; head; head = head->next) {
  189. if (thread_id == threadid_from_target(head->target))
  190. return head->target;
  191. }
  192. } else if (thread_id == threadid_from_target(target)) {
  193. return target;
  194. }
  195. return NULL;
  196. }
  197. static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
  198. struct rtos_reg **rtos_reg_list, int *rtos_reg_list_size)
  199. {
  200. if (!rtos)
  201. return ERROR_FAIL;
  202. struct target *target = rtos->target;
  203. struct target *curr = hwthread_find_thread(target, thread_id);
  204. if (!curr)
  205. return ERROR_FAIL;
  206. if (!target_was_examined(curr))
  207. return ERROR_FAIL;
  208. int reg_list_size;
  209. struct reg **reg_list;
  210. int retval = target_get_gdb_reg_list(curr, &reg_list, &reg_list_size,
  211. REG_CLASS_GENERAL);
  212. if (retval != ERROR_OK)
  213. return retval;
  214. int j = 0;
  215. for (int i = 0; i < reg_list_size; i++) {
  216. if (!reg_list[i] || reg_list[i]->exist == false || reg_list[i]->hidden)
  217. continue;
  218. j++;
  219. }
  220. *rtos_reg_list_size = j;
  221. *rtos_reg_list = calloc(*rtos_reg_list_size, sizeof(struct rtos_reg));
  222. if (!*rtos_reg_list) {
  223. free(reg_list);
  224. return ERROR_FAIL;
  225. }
  226. j = 0;
  227. for (int i = 0; i < reg_list_size; i++) {
  228. if (!reg_list[i] || reg_list[i]->exist == false || reg_list[i]->hidden)
  229. continue;
  230. (*rtos_reg_list)[j].number = (*reg_list)[i].number;
  231. (*rtos_reg_list)[j].size = (*reg_list)[i].size;
  232. memcpy((*rtos_reg_list)[j].value, (*reg_list)[i].value,
  233. ((*reg_list)[i].size + 7) / 8);
  234. j++;
  235. }
  236. free(reg_list);
  237. return ERROR_OK;
  238. }
  239. static int hwthread_get_thread_reg(struct rtos *rtos, int64_t thread_id,
  240. uint32_t reg_num, struct rtos_reg *rtos_reg)
  241. {
  242. if (!rtos)
  243. return ERROR_FAIL;
  244. struct target *target = rtos->target;
  245. struct target *curr = hwthread_find_thread(target, thread_id);
  246. if (!curr) {
  247. LOG_ERROR("Couldn't find RTOS thread for id %" PRId64 ".", thread_id);
  248. return ERROR_FAIL;
  249. }
  250. if (!target_was_examined(curr)) {
  251. LOG_ERROR("Target %d hasn't been examined yet.", curr->coreid);
  252. return ERROR_FAIL;
  253. }
  254. struct reg *reg = register_get_by_number(curr->reg_cache, reg_num, true);
  255. if (!reg) {
  256. LOG_ERROR("Couldn't find register %" PRIu32 " in thread %" PRId64 ".", reg_num,
  257. thread_id);
  258. return ERROR_FAIL;
  259. }
  260. if (reg->type->get(reg) != ERROR_OK)
  261. return ERROR_FAIL;
  262. rtos_reg->number = reg->number;
  263. rtos_reg->size = reg->size;
  264. unsigned bytes = (reg->size + 7) / 8;
  265. assert(bytes <= sizeof(rtos_reg->value));
  266. memcpy(rtos_reg->value, reg->value, bytes);
  267. return ERROR_OK;
  268. }
  269. static int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value)
  270. {
  271. if (!rtos)
  272. return ERROR_FAIL;
  273. struct target *target = rtos->target;
  274. struct target *curr = hwthread_find_thread(target, rtos->current_thread);
  275. if (!curr)
  276. return ERROR_FAIL;
  277. struct reg *reg = register_get_by_number(curr->reg_cache, reg_num, true);
  278. if (!reg)
  279. return ERROR_FAIL;
  280. return reg->type->set(reg, reg_value);
  281. }
  282. static int hwthread_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
  283. {
  284. /* return an empty list, we don't have any symbols to look up */
  285. *symbol_list = calloc(1, sizeof(struct symbol_table_elem));
  286. (*symbol_list)[0].symbol_name = NULL;
  287. return 0;
  288. }
  289. static int hwthread_target_for_threadid(struct connection *connection, int64_t thread_id, struct target **p_target)
  290. {
  291. struct target *target = get_target_from_connection(connection);
  292. struct target *curr = hwthread_find_thread(target, thread_id);
  293. if (!curr)
  294. return ERROR_FAIL;
  295. *p_target = curr;
  296. return ERROR_OK;
  297. }
  298. static bool hwthread_detect_rtos(struct target *target)
  299. {
  300. /* always return 0, avoid auto-detection */
  301. return false;
  302. }
  303. static int hwthread_thread_packet(struct connection *connection, const char *packet, int packet_size)
  304. {
  305. struct target *target = get_target_from_connection(connection);
  306. struct target *curr = NULL;
  307. int64_t current_threadid;
  308. if (packet[0] == 'H' && packet[1] == 'g') {
  309. sscanf(packet, "Hg%16" SCNx64, &current_threadid);
  310. if (current_threadid > 0) {
  311. if (hwthread_target_for_threadid(connection, current_threadid, &curr) != ERROR_OK) {
  312. LOG_ERROR("hwthread: cannot find thread id %"PRId64, current_threadid);
  313. gdb_put_packet(connection, "E01", 3);
  314. return ERROR_FAIL;
  315. }
  316. target->rtos->current_thread = current_threadid;
  317. } else
  318. if (current_threadid == 0 || current_threadid == -1)
  319. target->rtos->current_thread = threadid_from_target(target);
  320. target->rtos->current_threadid = current_threadid;
  321. gdb_put_packet(connection, "OK", 2);
  322. return ERROR_OK;
  323. }
  324. return rtos_thread_packet(connection, packet, packet_size);
  325. }
  326. static int hwthread_create(struct target *target)
  327. {
  328. LOG_INFO("Hardware thread awareness created");
  329. target->rtos->rtos_specific_params = NULL;
  330. target->rtos->current_thread = 0;
  331. target->rtos->thread_details = NULL;
  332. target->rtos->gdb_target_for_threadid = hwthread_target_for_threadid;
  333. target->rtos->gdb_thread_packet = hwthread_thread_packet;
  334. return 0;
  335. }
  336. static int hwthread_read_buffer(struct rtos *rtos, target_addr_t address,
  337. uint32_t size, uint8_t *buffer)
  338. {
  339. if (!rtos)
  340. return ERROR_FAIL;
  341. struct target *target = rtos->target;
  342. struct target *curr = hwthread_find_thread(target, rtos->current_thread);
  343. if (!curr)
  344. return ERROR_FAIL;
  345. return target_read_buffer(curr, address, size, buffer);
  346. }
  347. static int hwthread_write_buffer(struct rtos *rtos, target_addr_t address,
  348. uint32_t size, const uint8_t *buffer)
  349. {
  350. if (!rtos)
  351. return ERROR_FAIL;
  352. struct target *target = rtos->target;
  353. struct target *curr = hwthread_find_thread(target, rtos->current_thread);
  354. if (!curr)
  355. return ERROR_FAIL;
  356. return target_write_buffer(curr, address, size, buffer);
  357. }