Changeset a35b458 in mainline for kernel/generic/src/udebug
- Timestamp:
- 2018-03-02T20:10:49Z (8 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- f1380b7
- Parents:
- 3061bc1
- git-author:
- Jiří Zárevúcky <zarevucky.jiri@…> (2018-02-28 17:38:31)
- git-committer:
- Jiří Zárevúcky <zarevucky.jiri@…> (2018-03-02 20:10:49)
- Location:
- kernel/generic/src/udebug
- Files:
-
- 2 edited
-
udebug.c (modified) (26 diffs)
-
udebug_ops.c (modified) (29 diffs)
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/src/udebug/udebug.c
r3061bc1 ra35b458 75 75 waitq_initialize(&ut->go_wq); 76 76 condvar_initialize(&ut->active_cv); 77 77 78 78 ut->go_call = NULL; 79 79 ut->uspace_state = NULL; … … 96 96 { 97 97 ipl_t ipl = waitq_sleep_prepare(wq); 98 98 99 99 wq->missed_wakeups = 0; /* Enforce blocking. */ 100 100 bool blocked; … … 119 119 assert(THREAD); 120 120 assert(TASK); 121 121 122 122 mutex_lock(&TASK->udebug.lock); 123 123 124 124 int nsc = --TASK->udebug.not_stoppable_count; 125 125 126 126 /* Lock order OK, THREAD->udebug.lock is after TASK->udebug.lock */ 127 127 mutex_lock(&THREAD->udebug.lock); 128 128 assert(THREAD->udebug.stoppable == false); 129 129 THREAD->udebug.stoppable = true; 130 130 131 131 if ((TASK->udebug.dt_state == UDEBUG_TS_BEGINNING) && (nsc == 0)) { 132 132 /* … … 135 135 * 136 136 */ 137 137 138 138 call_t *db_call = TASK->udebug.begin_call; 139 139 assert(db_call); 140 140 141 141 TASK->udebug.dt_state = UDEBUG_TS_ACTIVE; 142 142 TASK->udebug.begin_call = NULL; 143 143 144 144 IPC_SET_RETVAL(db_call->data, 0); 145 145 ipc_answer(&TASK->answerbox, db_call); … … 148 148 * Active debugging session 149 149 */ 150 150 151 151 if (THREAD->udebug.active == true && 152 152 THREAD->udebug.go == false) { … … 155 155 * 156 156 */ 157 157 158 158 /* Make sure nobody takes this call away from us */ 159 159 call_t *go_call = THREAD->udebug.go_call; 160 160 THREAD->udebug.go_call = NULL; 161 161 assert(go_call); 162 162 163 163 IPC_SET_RETVAL(go_call->data, 0); 164 164 IPC_SET_ARG1(go_call->data, UDEBUG_EVENT_STOP); 165 165 166 166 THREAD->udebug.cur_event = UDEBUG_EVENT_STOP; 167 167 ipc_answer(&TASK->answerbox, go_call); 168 168 } 169 169 } 170 170 171 171 mutex_unlock(&THREAD->udebug.lock); 172 172 mutex_unlock(&TASK->udebug.lock); … … 185 185 mutex_lock(&TASK->udebug.lock); 186 186 mutex_lock(&THREAD->udebug.lock); 187 187 188 188 if ((THREAD->udebug.active) && (THREAD->udebug.go == false)) { 189 189 mutex_unlock(&THREAD->udebug.lock); 190 190 mutex_unlock(&TASK->udebug.lock); 191 191 192 192 udebug_wait_for_go(&THREAD->udebug.go_wq); 193 193 194 194 goto restart; 195 195 /* Must try again - have to lose stoppability atomically. */ … … 198 198 assert(THREAD->udebug.stoppable == true); 199 199 THREAD->udebug.stoppable = false; 200 200 201 201 mutex_unlock(&THREAD->udebug.lock); 202 202 mutex_unlock(&TASK->udebug.lock); … … 228 228 udebug_event_t etype = 229 229 end_variant ? UDEBUG_EVENT_SYSCALL_E : UDEBUG_EVENT_SYSCALL_B; 230 230 231 231 mutex_lock(&TASK->udebug.lock); 232 232 mutex_lock(&THREAD->udebug.lock); 233 233 234 234 /* Must only generate events when in debugging session and is go. */ 235 235 if (THREAD->udebug.active != true || THREAD->udebug.go == false || … … 239 239 return; 240 240 } 241 241 242 242 /* Fill in the GO response. */ 243 243 call_t *call = THREAD->udebug.go_call; 244 244 THREAD->udebug.go_call = NULL; 245 245 246 246 IPC_SET_RETVAL(call->data, 0); 247 247 IPC_SET_ARG1(call->data, etype); 248 248 IPC_SET_ARG2(call->data, id); 249 249 IPC_SET_ARG3(call->data, rc); 250 250 251 251 THREAD->udebug.syscall_args[0] = a1; 252 252 THREAD->udebug.syscall_args[1] = a2; … … 255 255 THREAD->udebug.syscall_args[4] = a5; 256 256 THREAD->udebug.syscall_args[5] = a6; 257 257 258 258 /* 259 259 * Make sure udebug.go is false when going to sleep … … 264 264 THREAD->udebug.go = false; 265 265 THREAD->udebug.cur_event = etype; 266 266 267 267 ipc_answer(&TASK->answerbox, call); 268 268 269 269 mutex_unlock(&THREAD->udebug.lock); 270 270 mutex_unlock(&TASK->udebug.lock); 271 271 272 272 udebug_wait_for_go(&THREAD->udebug.go_wq); 273 273 } … … 294 294 mutex_lock(&TASK->udebug.lock); 295 295 mutex_lock(&THREAD->udebug.lock); 296 296 297 297 thread_attach(thread, task); 298 298 299 299 LOG("Check state"); 300 300 301 301 /* Must only generate events when in debugging session */ 302 302 if (THREAD->udebug.active != true) { … … 304 304 THREAD->udebug.active ? "Yes(+)" : "No", 305 305 THREAD->udebug.go ? "Yes(-)" : "No"); 306 306 307 307 mutex_unlock(&THREAD->udebug.lock); 308 308 mutex_unlock(&TASK->udebug.lock); 309 309 return; 310 310 } 311 311 312 312 LOG("Trigger event"); 313 313 314 314 call_t *call = THREAD->udebug.go_call; 315 315 316 316 THREAD->udebug.go_call = NULL; 317 317 IPC_SET_RETVAL(call->data, 0); 318 318 IPC_SET_ARG1(call->data, UDEBUG_EVENT_THREAD_B); 319 319 IPC_SET_ARG2(call->data, (sysarg_t) thread); 320 320 321 321 /* 322 322 * Make sure udebug.go is false when going to sleep … … 327 327 THREAD->udebug.go = false; 328 328 THREAD->udebug.cur_event = UDEBUG_EVENT_THREAD_B; 329 329 330 330 ipc_answer(&TASK->answerbox, call); 331 331 332 332 mutex_unlock(&THREAD->udebug.lock); 333 333 mutex_unlock(&TASK->udebug.lock); 334 334 335 335 LOG("Wait for Go"); 336 336 udebug_wait_for_go(&THREAD->udebug.go_wq); … … 347 347 mutex_lock(&TASK->udebug.lock); 348 348 mutex_lock(&THREAD->udebug.lock); 349 349 350 350 LOG("Check state"); 351 351 352 352 /* Must only generate events when in debugging session. */ 353 353 if (THREAD->udebug.active != true) { … … 355 355 THREAD->udebug.active ? "Yes" : "No", 356 356 THREAD->udebug.go ? "Yes" : "No"); 357 357 358 358 mutex_unlock(&THREAD->udebug.lock); 359 359 mutex_unlock(&TASK->udebug.lock); 360 360 return; 361 361 } 362 362 363 363 LOG("Trigger event"); 364 364 365 365 call_t *call = THREAD->udebug.go_call; 366 366 367 367 THREAD->udebug.go_call = NULL; 368 368 IPC_SET_RETVAL(call->data, 0); 369 369 IPC_SET_ARG1(call->data, UDEBUG_EVENT_THREAD_E); 370 370 371 371 /* Prevent any further debug activity in thread. */ 372 372 THREAD->udebug.active = false; 373 373 THREAD->udebug.cur_event = 0; /* None */ 374 374 THREAD->udebug.go = false; /* Set to initial value */ 375 375 376 376 ipc_answer(&TASK->answerbox, call); 377 377 378 378 mutex_unlock(&THREAD->udebug.lock); 379 379 mutex_unlock(&TASK->udebug.lock); 380 380 381 381 /* 382 382 * This event does not sleep - debugging has finished … … 405 405 return EINVAL; 406 406 } 407 407 408 408 LOG("Task %" PRIu64, task->taskid); 409 409 410 410 /* Finish debugging of all userspace threads */ 411 411 list_foreach(task->threads, th_link, thread_t, thread) { 412 412 mutex_lock(&thread->udebug.lock); 413 413 414 414 /* Only process userspace threads. */ 415 415 if (thread->uspace) { … … 417 417 thread->udebug.active = false; 418 418 thread->udebug.cur_event = 0; /* None */ 419 419 420 420 /* Is the thread still go? */ 421 421 if (thread->udebug.go == true) { … … 426 426 */ 427 427 thread->udebug.go = false; 428 428 429 429 /* Answer GO call */ 430 430 LOG("Answer GO call with EVENT_FINISHED."); 431 431 432 432 IPC_SET_RETVAL(thread->udebug.go_call->data, 0); 433 433 IPC_SET_ARG1(thread->udebug.go_call->data, 434 434 UDEBUG_EVENT_FINISHED); 435 435 436 436 ipc_answer(&task->answerbox, thread->udebug.go_call); 437 437 thread->udebug.go_call = NULL; … … 442 442 * 443 443 */ 444 444 445 445 /* 446 446 * thread's lock must not be held when calling … … 450 450 waitq_wakeup(&thread->udebug.go_wq, WAKEUP_FIRST); 451 451 } 452 452 453 453 mutex_unlock(&thread->udebug.lock); 454 454 condvar_broadcast(&thread->udebug.active_cv); … … 456 456 mutex_unlock(&thread->udebug.lock); 457 457 } 458 458 459 459 task->udebug.dt_state = UDEBUG_TS_INACTIVE; 460 460 task->udebug.debugger = NULL; 461 461 462 462 return 0; 463 463 } … … 474 474 { 475 475 udebug_stoppable_begin(); 476 476 477 477 /* Wait until a debugger attends to us. */ 478 478 mutex_lock(&THREAD->udebug.lock); … … 480 480 condvar_wait(&THREAD->udebug.active_cv, &THREAD->udebug.lock); 481 481 mutex_unlock(&THREAD->udebug.lock); 482 482 483 483 /* Make sure the debugging session is over before proceeding. */ 484 484 mutex_lock(&THREAD->udebug.lock); … … 486 486 condvar_wait(&THREAD->udebug.active_cv, &THREAD->udebug.lock); 487 487 mutex_unlock(&THREAD->udebug.lock); 488 488 489 489 udebug_stoppable_end(); 490 490 } -
kernel/generic/src/udebug/udebug_ops.c
r3061bc1 ra35b458 82 82 { 83 83 mutex_lock(&TASK->udebug.lock); 84 84 85 85 /* thread_exists() must be called with threads_lock held */ 86 86 irq_spinlock_lock(&threads_lock, true); 87 87 88 88 if (!thread_exists(thread)) { 89 89 irq_spinlock_unlock(&threads_lock, true); … … 91 91 return ENOENT; 92 92 } 93 93 94 94 /* thread->lock is enough to ensure the thread's existence */ 95 95 irq_spinlock_exchange(&threads_lock, &thread->lock); 96 96 97 97 /* Verify that 'thread' is a userspace thread. */ 98 98 if (!thread->uspace) { … … 102 102 return ENOENT; 103 103 } 104 104 105 105 /* Verify debugging state. */ 106 106 if (thread->udebug.active != true) { … … 110 110 return ENOENT; 111 111 } 112 112 113 113 /* 114 114 * Since the thread has active == true, TASK->udebug.lock … … 118 118 */ 119 119 irq_spinlock_unlock(&thread->lock, true); 120 120 121 121 /* Only mutex TASK->udebug.lock left. */ 122 122 123 123 /* Now verify that the thread belongs to the current task. */ 124 124 if (thread->task != TASK) { … … 127 127 return ENOENT; 128 128 } 129 129 130 130 /* 131 131 * Now we need to grab the thread's debug lock for synchronization … … 134 134 */ 135 135 mutex_lock(&thread->udebug.lock); 136 136 137 137 /* The big task mutex is no longer needed. */ 138 138 mutex_unlock(&TASK->udebug.lock); 139 139 140 140 if (thread->udebug.go != being_go) { 141 141 /* Not in debugging session or undesired GO state. */ … … 143 143 return EINVAL; 144 144 } 145 145 146 146 /* Only thread->udebug.lock left. */ 147 147 148 148 return EOK; /* All went well. */ 149 149 } … … 177 177 { 178 178 LOG("Debugging task %" PRIu64, TASK->taskid); 179 180 mutex_lock(&TASK->udebug.lock); 181 179 180 mutex_lock(&TASK->udebug.lock); 181 182 182 if (TASK->udebug.dt_state != UDEBUG_TS_INACTIVE) { 183 183 mutex_unlock(&TASK->udebug.lock); 184 184 return EBUSY; 185 185 } 186 186 187 187 TASK->udebug.dt_state = UDEBUG_TS_BEGINNING; 188 188 TASK->udebug.begin_call = call; 189 189 TASK->udebug.debugger = call->sender; 190 190 191 191 if (TASK->udebug.not_stoppable_count == 0) { 192 192 TASK->udebug.dt_state = UDEBUG_TS_ACTIVE; … … 195 195 } else 196 196 *active = false; /* only in beginning state */ 197 197 198 198 /* Set udebug.active on all of the task's userspace threads. */ 199 199 200 200 list_foreach(TASK->threads, th_link, thread_t, thread) { 201 201 mutex_lock(&thread->udebug.lock); … … 207 207 mutex_unlock(&thread->udebug.lock); 208 208 } 209 209 210 210 mutex_unlock(&TASK->udebug.lock); 211 211 return EOK; … … 222 222 { 223 223 LOG("Task %" PRIu64, TASK->taskid); 224 224 225 225 mutex_lock(&TASK->udebug.lock); 226 226 errno_t rc = udebug_task_cleanup(TASK); 227 227 mutex_unlock(&TASK->udebug.lock); 228 228 229 229 return rc; 230 230 } … … 242 242 { 243 243 LOG("mask = 0x%x", mask); 244 245 mutex_lock(&TASK->udebug.lock); 246 244 245 mutex_lock(&TASK->udebug.lock); 246 247 247 if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) { 248 248 mutex_unlock(&TASK->udebug.lock); 249 249 return EINVAL; 250 250 } 251 251 252 252 TASK->udebug.evmask = mask; 253 253 mutex_unlock(&TASK->udebug.lock); 254 254 255 255 return EOK; 256 256 } … … 272 272 if (rc != EOK) 273 273 return rc; 274 274 275 275 thread->udebug.go_call = call; 276 276 thread->udebug.go = true; 277 277 thread->udebug.cur_event = 0; /* none */ 278 278 279 279 /* 280 280 * Neither thread's lock nor threads_lock may be held during wakeup. … … 282 282 */ 283 283 waitq_wakeup(&thread->udebug.go_wq, WAKEUP_FIRST); 284 284 285 285 _thread_op_end(thread); 286 286 287 287 return EOK; 288 288 } … … 300 300 { 301 301 LOG("udebug_stop()"); 302 302 303 303 /* 304 304 * On success, this will lock thread->udebug.lock. Note that this … … 309 309 if (rc != EOK) 310 310 return rc; 311 311 312 312 /* Take GO away from the thread. */ 313 313 thread->udebug.go = false; 314 314 315 315 if (thread->udebug.stoppable != true) { 316 316 /* Answer will be sent when the thread becomes stoppable. */ … … 318 318 return EOK; 319 319 } 320 320 321 321 /* 322 322 * Answer GO call. 323 323 * 324 324 */ 325 325 326 326 /* Make sure nobody takes this call away from us. */ 327 327 call = thread->udebug.go_call; 328 328 thread->udebug.go_call = NULL; 329 329 330 330 IPC_SET_RETVAL(call->data, 0); 331 331 IPC_SET_ARG1(call->data, UDEBUG_EVENT_STOP); 332 332 333 333 THREAD->udebug.cur_event = UDEBUG_EVENT_STOP; 334 334 335 335 _thread_op_end(thread); 336 336 337 337 mutex_lock(&TASK->udebug.lock); 338 338 ipc_answer(&TASK->answerbox, call); 339 339 mutex_unlock(&TASK->udebug.lock); 340 340 341 341 return EOK; 342 342 } … … 368 368 { 369 369 LOG("udebug_thread_read()"); 370 370 371 371 /* Allocate a buffer to hold thread IDs */ 372 372 sysarg_t *id_buffer = malloc(buf_size + 1, 0); 373 374 mutex_lock(&TASK->udebug.lock); 375 373 374 mutex_lock(&TASK->udebug.lock); 375 376 376 /* Verify task state */ 377 377 if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) { … … 380 380 return EINVAL; 381 381 } 382 382 383 383 irq_spinlock_lock(&TASK->lock, true); 384 384 385 385 /* Copy down the thread IDs */ 386 386 387 387 size_t max_ids = buf_size / sizeof(sysarg_t); 388 388 size_t copied_ids = 0; 389 389 size_t extra_ids = 0; 390 390 391 391 /* FIXME: make sure the thread isn't past debug shutdown... */ 392 392 list_foreach(TASK->threads, th_link, thread_t, thread) { … … 394 394 bool uspace = thread->uspace; 395 395 irq_spinlock_unlock(&thread->lock, false); 396 396 397 397 /* Not interested in kernel threads. */ 398 398 if (!uspace) 399 399 continue; 400 400 401 401 if (copied_ids < max_ids) { 402 402 /* Using thread struct pointer as identification hash */ … … 405 405 extra_ids++; 406 406 } 407 407 408 408 irq_spinlock_unlock(&TASK->lock, true); 409 410 mutex_unlock(&TASK->udebug.lock); 411 409 410 mutex_unlock(&TASK->udebug.lock); 411 412 412 *buffer = id_buffer; 413 413 *stored = copied_ids * sizeof(sysarg_t); 414 414 *needed = (copied_ids + extra_ids) * sizeof(sysarg_t); 415 415 416 416 return EOK; 417 417 } … … 431 431 { 432 432 size_t name_size = str_size(TASK->name) + 1; 433 433 434 434 *data = malloc(name_size, 0); 435 435 *data_size = name_size; 436 436 437 437 memcpy(*data, TASK->name, name_size); 438 438 439 439 return EOK; 440 440 } … … 463 463 if (rc != EOK) 464 464 return rc; 465 465 466 466 /* Additionally we need to verify that we are inside a syscall. */ 467 467 if ((thread->udebug.cur_event != UDEBUG_EVENT_SYSCALL_B) && … … 470 470 return EINVAL; 471 471 } 472 472 473 473 /* Prepare a buffer to hold the arguments. */ 474 474 sysarg_t *arg_buffer = malloc(6 * sizeof(sysarg_t), 0); 475 475 476 476 /* Copy to a local buffer before releasing the lock. */ 477 477 memcpy(arg_buffer, thread->udebug.syscall_args, 6 * sizeof(sysarg_t)); 478 478 479 479 _thread_op_end(thread); 480 480 481 481 *buffer = arg_buffer; 482 482 return EOK; … … 506 506 if (rc != EOK) 507 507 return rc; 508 508 509 509 istate_t *state = thread->udebug.uspace_state; 510 510 if (state == NULL) { … … 512 512 return EBUSY; 513 513 } 514 514 515 515 /* Prepare a buffer to hold the data. */ 516 516 istate_t *state_buf = malloc(sizeof(istate_t), 0); 517 517 518 518 /* Copy to the allocated buffer */ 519 519 memcpy(state_buf, state, sizeof(istate_t)); 520 520 521 521 _thread_op_end(thread); 522 522 523 523 *buffer = (void *) state_buf; 524 524 return EOK; … … 540 540 /* Verify task state */ 541 541 mutex_lock(&TASK->udebug.lock); 542 542 543 543 if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) { 544 544 mutex_unlock(&TASK->udebug.lock); 545 545 return EBUSY; 546 546 } 547 547 548 548 void *data_buffer = malloc(n, 0); 549 549 550 550 /* 551 551 * NOTE: this is not strictly from a syscall... but that shouldn't … … 555 555 errno_t rc = copy_from_uspace(data_buffer, (void *) uspace_addr, n); 556 556 mutex_unlock(&TASK->udebug.lock); 557 557 558 558 if (rc != EOK) 559 559 return rc; 560 560 561 561 *buffer = data_buffer; 562 562 return EOK;
Note:
See TracChangeset
for help on using the changeset viewer.
