void vgaputi(int16_t x, int16_t y, uint8_t * p, int16_t w, int16_t h) { VGLBitmap *tmp; struct PendNode tmpn; struct PendNode *newn; static int pending_match = 0; tmpn.realx = virt2scrx(x); tmpn.realy = virt2scry(y); tmpn.realw = virt2scrw(w * 4); tmpn.realh = virt2scrh(h); newn = find_pending(&tmpn); if (newn == NULL) { newn = malloc(sizeof (struct PendNode)); memset(newn, 0x00, (sizeof (struct PendNode))); newn->realx = tmpn.realx; newn->realy = tmpn.realy; newn->realw = tmpn.realw; newn->realh = tmpn.realh; pendappend(newn); } else { rect_merge(newn, &tmpn); pending_match += 1; if (pending_match < 10 || pending_match % 50 == 0) { fprintf(stderr, "vgaputi: pending_match = %d\n", pending_match); } } memcpy(&tmp, p, (sizeof(VGLBitmap *))); VGLBitmapCopy(tmp, 0, 0, sVGLDisplay, tmpn.realx, tmpn.realy, tmpn.realw, tmpn.realh); }
static void player_set_setting(struct media_player *mp, GDBusPendingPropertySet id, const char *key, const char *value) { struct player_callback *cb = mp->cb; struct pending_req *p; if (cb == NULL || cb->cbs->set_setting == NULL) { g_dbus_pending_property_error(id, ERROR_INTERFACE ".NotSupported", "Operation is not supported"); return; } p = find_pending(mp, key); if (p != NULL) { g_dbus_pending_property_error(id, ERROR_INTERFACE ".InProgress", "Operation already in progress"); return; } if (!cb->cbs->set_setting(mp, key, value, cb->user_data)) { g_dbus_pending_property_error(id, ERROR_INTERFACE ".InvalidArguments", "Invalid arguments in method call"); return; } p = pending_new(id, key, value); mp->pending = g_slist_append(mp->pending, p); }
void media_player_set_setting(struct media_player *mp, const char *key, const char *value) { char *curval; struct pending_req *p; DBG("%s: %s", key, value); if (strcasecmp(key, "Error") == 0) { p = g_slist_nth_data(mp->pending, 0); if (p == NULL) return; g_dbus_pending_property_error(p->id, ERROR_INTERFACE ".Failed", value); goto send; } curval = g_hash_table_lookup(mp->settings, key); if (g_strcmp0(curval, value) == 0) goto done; g_hash_table_replace(mp->settings, g_strdup(key), g_strdup(value)); g_dbus_emit_property_changed(btd_get_dbus_connection(), mp->path, MEDIA_PLAYER_INTERFACE, key); done: p = find_pending(mp, key); if (p == NULL) return; if (strcasecmp(value, p->value) == 0) g_dbus_pending_property_success(p->id); else g_dbus_pending_property_error(p->id, ERROR_INTERFACE ".NotSupported", "Operation is not supported"); send: mp->pending = g_slist_remove(mp->pending, p); g_free(p); return; }
static void blk_full(MACRO_PROT_ARGS) { int la, nl, parsed; struct mdoc_arg *arg; struct roff_node *blk; /* Our own or a broken block. */ struct roff_node *head; /* Our own head. */ struct roff_node *body; /* Our own body. */ struct roff_node *n; enum margserr ac, lac; char *p; nl = MDOC_NEWLINE & mdoc->flags; if (buf[*pos] == '\0' && (tok == MDOC_Sh || tok == MDOC_Ss)) { mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, line, ppos, mdoc_macronames[tok]); return; } if ( ! (mdoc_macros[tok].flags & MDOC_EXPLICIT)) { /* Here, tok is one of Sh Ss Nm Nd It. */ blk = NULL; for (n = mdoc->last; n != NULL; n = n->parent) { if (n->flags & MDOC_ENDED) { if ( ! (n->flags & MDOC_VALID)) n->flags |= MDOC_BROKEN; continue; } if (n->type != ROFFT_BLOCK) continue; if (tok == MDOC_It && n->tok == MDOC_Bl) { if (blk != NULL) { mandoc_vmsg(MANDOCERR_BLK_BROKEN, mdoc->parse, line, ppos, "It breaks %s", mdoc_macronames[blk->tok]); rew_pending(mdoc, blk); } break; } if (mdoc_macros[n->tok].flags & MDOC_EXPLICIT) { switch (tok) { case MDOC_Sh: case MDOC_Ss: mandoc_vmsg(MANDOCERR_BLK_BROKEN, mdoc->parse, line, ppos, "%s breaks %s", mdoc_macronames[tok], mdoc_macronames[n->tok]); rew_pending(mdoc, n); n = mdoc->last; continue; case MDOC_It: /* Delay in case it's astray. */ blk = n; continue; default: break; } break; } /* Here, n is one of Sh Ss Nm Nd It. */ if (tok != MDOC_Sh && (n->tok == MDOC_Sh || (tok != MDOC_Ss && (n->tok == MDOC_Ss || (tok != MDOC_It && n->tok == MDOC_It))))) break; /* Item breaking an explicit block. */ if (blk != NULL) { mandoc_vmsg(MANDOCERR_BLK_BROKEN, mdoc->parse, line, ppos, "It breaks %s", mdoc_macronames[blk->tok]); rew_pending(mdoc, blk); blk = NULL; } /* Close out prior implicit scopes. */ rew_last(mdoc, n); } /* Skip items outside lists. */ if (tok == MDOC_It && (n == NULL || n->tok != MDOC_Bl)) { mandoc_vmsg(MANDOCERR_IT_STRAY, mdoc->parse, line, ppos, "It %s", buf + *pos); roff_elem_alloc(mdoc, line, ppos, MDOC_br); rew_elem(mdoc, MDOC_br); return; } } /* * This routine accommodates implicitly- and explicitly-scoped * macro openings. Implicit ones first close out prior scope * (seen above). Delay opening the head until necessary to * allow leading punctuation to print. Special consideration * for `It -column', which has phrase-part syntax instead of * regular child nodes. */ mdoc_argv(mdoc, line, tok, &arg, pos, buf); blk = mdoc_block_alloc(mdoc, line, ppos, tok, arg); head = body = NULL; /* * Exception: Heads of `It' macros in `-diag' lists are not * parsed, even though `It' macros in general are parsed. */ parsed = tok != MDOC_It || mdoc->last->parent->tok != MDOC_Bl || mdoc->last->parent->norm->Bl.type != LIST_diag; /* * The `Nd' macro has all arguments in its body: it's a hybrid * of block partial-explicit and full-implicit. Stupid. */ if (tok == MDOC_Nd) { head = roff_head_alloc(mdoc, line, ppos, tok); rew_last(mdoc, head); body = roff_body_alloc(mdoc, line, ppos, tok); } if (tok == MDOC_Bk) mdoc->flags |= MDOC_KEEP; ac = ARGS_EOLN; for (;;) { /* * If we are right after a tab character, * do not parse the first word for macros. */ if (mdoc->flags & MDOC_PHRASEQN) { mdoc->flags &= ~MDOC_PHRASEQN; mdoc->flags |= MDOC_PHRASEQF; } la = *pos; lac = ac; ac = mdoc_args(mdoc, line, pos, buf, tok, &p); if (ac == ARGS_EOLN) { if (lac != ARGS_PHRASE || ! (mdoc->flags & MDOC_PHRASEQF)) break; /* * This line ends in a tab; start the next * column now, with a leading blank. */ if (body != NULL) rew_last(mdoc, body); body = roff_body_alloc(mdoc, line, ppos, tok); roff_word_alloc(mdoc, line, ppos, "\\&"); break; } if (tok == MDOC_Bd || tok == MDOC_Bk) { mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, line, la, "%s ... %s", mdoc_macronames[tok], buf + la); break; } if (tok == MDOC_Rs) { mandoc_vmsg(MANDOCERR_ARG_SKIP, mdoc->parse, line, la, "Rs %s", buf + la); break; } if (ac == ARGS_PUNCT) break; /* * Emit leading punctuation (i.e., punctuation before * the ROFFT_HEAD) for non-phrase types. */ if (head == NULL && ac != ARGS_PHRASE && ac != ARGS_QWORD && mdoc_isdelim(p) == DELIM_OPEN) { dword(mdoc, line, la, p, DELIM_OPEN, 0); continue; } /* Open a head if one hasn't been opened. */ if (head == NULL) head = roff_head_alloc(mdoc, line, ppos, tok); if (ac == ARGS_PHRASE) { /* * If we haven't opened a body yet, rewind the * head; if we have, rewind that instead. */ rew_last(mdoc, body == NULL ? head : body); body = roff_body_alloc(mdoc, line, ppos, tok); /* Process to the tab or to the end of the line. */ mdoc->flags |= MDOC_PHRASE; parse_rest(mdoc, TOKEN_NONE, line, &la, buf); mdoc->flags &= ~MDOC_PHRASE; /* There may have been `Ta' macros. */ while (body->next != NULL) body = body->next; continue; } if (macro_or_word(mdoc, tok, line, la, pos, buf, parsed)) break; } if (blk->flags & MDOC_VALID) return; if (head == NULL) head = roff_head_alloc(mdoc, line, ppos, tok); if (nl && tok != MDOC_Bd && tok != MDOC_Bl && tok != MDOC_Rs) append_delims(mdoc, line, pos, buf); if (body != NULL) goto out; if (find_pending(mdoc, tok, line, ppos, head)) return; /* Close out scopes to remain in a consistent state. */ rew_last(mdoc, head); body = roff_body_alloc(mdoc, line, ppos, tok); out: if (mdoc->flags & MDOC_FREECOL) { rew_last(mdoc, body); rew_last(mdoc, blk); mdoc->flags &= ~MDOC_FREECOL; } }
/* * Close out block partial/full explicit. */ static void blk_exp_close(MACRO_PROT_ARGS) { struct roff_node *body; /* Our own body. */ struct roff_node *endbody; /* Our own end marker. */ struct roff_node *itblk; /* An It block starting later. */ struct roff_node *later; /* A sub-block starting later. */ struct roff_node *n; /* Search back to our block. */ struct roff_node *target; /* For find_pending(). */ int j, lastarg, maxargs, nl, pending; enum margserr ac; int atok, ntok; char *p; nl = MDOC_NEWLINE & mdoc->flags; switch (tok) { case MDOC_Ec: maxargs = 1; break; case MDOC_Ek: mdoc->flags &= ~MDOC_KEEP; /* FALLTHROUGH */ default: maxargs = 0; break; } /* * Search backwards for beginnings of blocks, * both of our own and of pending sub-blocks. */ atok = rew_alt(tok); body = endbody = itblk = later = NULL; for (n = mdoc->last; n; n = n->parent) { if (n->flags & MDOC_ENDED) { if ( ! (n->flags & MDOC_VALID)) n->flags |= MDOC_BROKEN; continue; } /* Remember the start of our own body. */ if (n->type == ROFFT_BODY && atok == n->tok) { if (n->end == ENDBODY_NOT) body = n; continue; } if (n->type != ROFFT_BLOCK || n->tok == MDOC_Nm) continue; if (n->tok == MDOC_It) { itblk = n; continue; } if (atok == n->tok) { assert(body); /* * Found the start of our own block. * When there is no pending sub block, * just proceed to closing out. */ if (later == NULL || (tok == MDOC_El && itblk == NULL)) break; /* * When there is a pending sub block, postpone * closing out the current block until the * rew_pending() closing out the sub-block. * Mark the place where the formatting - but not * the scope - of the current block ends. */ mandoc_vmsg(MANDOCERR_BLK_NEST, mdoc->parse, line, ppos, "%s breaks %s", mdoc_macronames[atok], mdoc_macronames[later->tok]); endbody = mdoc_endbody_alloc(mdoc, line, ppos, atok, body, ENDBODY_SPACE); if (tok == MDOC_El) itblk->flags |= MDOC_ENDED | MDOC_BROKEN; /* * If a block closing macro taking arguments * breaks another block, put the arguments * into the end marker. */ if (maxargs) mdoc->next = ROFF_NEXT_CHILD; break; } /* Explicit blocks close out description lines. */ if (n->tok == MDOC_Nd) { rew_last(mdoc, n); continue; } /* Breaking an open sub block. */ n->flags |= MDOC_BROKEN; if (later == NULL) later = n; } if (body == NULL) { mandoc_msg(MANDOCERR_BLK_NOTOPEN, mdoc->parse, line, ppos, mdoc_macronames[tok]); if (later != NULL) later->flags &= ~MDOC_BROKEN; if (maxargs && endbody == NULL) { /* * Stray .Ec without previous .Eo: * Break the output line, keep the arguments. */ roff_elem_alloc(mdoc, line, ppos, MDOC_br); rew_elem(mdoc, MDOC_br); } } else if (endbody == NULL) { rew_last(mdoc, body); if (maxargs) mdoc_tail_alloc(mdoc, line, ppos, atok); } if ( ! (mdoc_macros[tok].flags & MDOC_PARSED)) { if (buf[*pos] != '\0') mandoc_vmsg(MANDOCERR_ARG_SKIP, mdoc->parse, line, ppos, "%s %s", mdoc_macronames[tok], buf + *pos); if (endbody == NULL && n != NULL) rew_pending(mdoc, n); return; } if (endbody != NULL) n = endbody; ntok = TOKEN_NONE; for (j = 0; ; j++) { lastarg = *pos; if (j == maxargs && n != NULL) rew_last(mdoc, n); ac = mdoc_args(mdoc, line, pos, buf, tok, &p); if (ac == ARGS_PUNCT || ac == ARGS_EOLN) break; ntok = ac == ARGS_QWORD ? TOKEN_NONE : lookup(mdoc, tok, line, lastarg, p); if (ntok == TOKEN_NONE) { dword(mdoc, line, lastarg, p, DELIM_MAX, MDOC_JOIN & mdoc_macros[tok].flags); continue; } if (n != NULL) rew_last(mdoc, n); mdoc->flags &= ~MDOC_NEWLINE; mdoc_macro(mdoc, ntok, line, lastarg, pos, buf); break; } if (n != NULL) { if (ntok != TOKEN_NONE && n->flags & MDOC_BROKEN) { target = n; do target = target->parent; while ( ! (target->flags & MDOC_ENDED)); pending = find_pending(mdoc, ntok, line, ppos, target); } else pending = 0; if ( ! pending) rew_pending(mdoc, n); } if (nl) append_delims(mdoc, line, pos, buf); }
static void blk_part_imp(MACRO_PROT_ARGS) { int la, nl; enum margserr ac; char *p; struct roff_node *blk; /* saved block context */ struct roff_node *body; /* saved body context */ struct roff_node *n; nl = MDOC_NEWLINE & mdoc->flags; /* * A macro that spans to the end of the line. This is generally * (but not necessarily) called as the first macro. The block * has a head as the immediate child, which is always empty, * followed by zero or more opening punctuation nodes, then the * body (which may be empty, depending on the macro), then zero * or more closing punctuation nodes. */ blk = mdoc_block_alloc(mdoc, line, ppos, tok, NULL); rew_last(mdoc, roff_head_alloc(mdoc, line, ppos, tok)); /* * Open the body scope "on-demand", that is, after we've * processed all our the leading delimiters (open parenthesis, * etc.). */ for (body = NULL; ; ) { la = *pos; ac = mdoc_args(mdoc, line, pos, buf, tok, &p); if (ac == ARGS_EOLN || ac == ARGS_PUNCT) break; if (body == NULL && ac != ARGS_QWORD && mdoc_isdelim(p) == DELIM_OPEN) { dword(mdoc, line, la, p, DELIM_OPEN, 0); continue; } if (body == NULL) body = roff_body_alloc(mdoc, line, ppos, tok); if (macro_or_word(mdoc, tok, line, la, pos, buf, 1)) break; } if (body == NULL) body = roff_body_alloc(mdoc, line, ppos, tok); if (find_pending(mdoc, tok, line, ppos, body)) return; rew_last(mdoc, body); if (nl) append_delims(mdoc, line, pos, buf); rew_pending(mdoc, blk); /* Move trailing .Ns out of scope. */ for (n = body->child; n && n->next; n = n->next) /* Do nothing. */ ; if (n && n->tok == MDOC_Ns) mdoc_node_relink(mdoc, n); }
static void event_pid_stopped(pid_t pid, int signal, int event, int syscall) { int stopped_by_exception = 0; unsigned long msg = 0; Context * ctx = NULL; Context * ctx2 = NULL; trace(LOG_EVENTS, "event: pid %d stopped, signal %d", pid, signal); ctx = context_find_from_pid(pid, 1); if (ctx == NULL) { ctx = find_pending(pid); if (ctx != NULL) { Context * prs = ctx; assert(prs->ref_count == 0); ctx = create_context(pid2id(pid, pid)); EXT(ctx)->pid = pid; EXT(ctx)->regs = (REG_SET *)loc_alloc(sizeof(REG_SET)); ctx->pending_intercept = 1; ctx->mem = prs; ctx->parent = prs; ctx->big_endian = prs->big_endian; prs->ref_count++; list_add_last(&ctx->cldl, &prs->children); link_context(prs); link_context(ctx); send_context_created_event(prs); send_context_created_event(ctx); if (EXT(prs)->attach_callback) { EXT(prs)->attach_callback(0, prs, EXT(prs)->attach_data); EXT(prs)->attach_callback = NULL; EXT(prs)->attach_data = NULL; } } } if (ctx == NULL) return; assert(!ctx->exited); assert(!EXT(ctx)->attach_callback); if (signal != SIGSTOP && signal != SIGTRAP) { sigset_set(&ctx->pending_signals, signal, 1); if (sigset_get(&ctx->sig_dont_stop, signal) == 0) { ctx->pending_intercept = 1; stopped_by_exception = 1; } } if (ctx->stopped) { send_context_changed_event(ctx); } else { thread_state_t state; unsigned int state_count; ContextAddress pc0 = 0; ContextAddress pc1 = 0; assert(!EXT(ctx)->regs_dirty); EXT(ctx)->end_of_step = 0; EXT(ctx)->ptrace_event = event; ctx->signal = signal; ctx->stopped_by_bp = 0; ctx->stopped_by_exception = stopped_by_exception; ctx->stopped = 1; if (EXT(ctx)->regs_error) { release_error_report(EXT(ctx)->regs_error); EXT(ctx)->regs_error = NULL; } else { pc0 = get_regs_PC(ctx); } if (thread_get_state(EXT(ctx)->pid, x86_THREAD_STATE32, EXT(ctx)->regs, &state_count) != KERN_SUCCESS) { assert(errno != 0); EXT(ctx)->regs_error = get_error_report(errno); trace(LOG_ALWAYS, "error: thread_get_state failed; id %s, error %d %s", ctx->id, errno, errno_to_str(errno)); } else { pc1 = get_regs_PC(ctx); } if (!EXT(ctx)->syscall_enter || EXT(ctx)->regs_error || pc0 != pc1) { EXT(ctx)->syscall_enter = 0; EXT(ctx)->syscall_exit = 0; EXT(ctx)->syscall_id = 0; EXT(ctx)->syscall_pc = 0; } trace(LOG_EVENTS, "event: pid %d stopped at PC = %#lx", pid, pc1); if (signal == SIGTRAP && event == 0 && !syscall) { size_t break_size = 0; get_break_instruction(ctx, &break_size); ctx->stopped_by_bp = !EXT(ctx)->regs_error && is_breakpoint_address(ctx, pc1 - break_size); EXT(ctx)->end_of_step = !ctx->stopped_by_bp && EXT(ctx)->pending_step; if (ctx->stopped_by_bp) set_regs_PC(ctx, pc1 - break_size); } EXT(ctx)->pending_step = 0; send_context_stopped_event(ctx); } }
static void event_pid_exited(pid_t pid, int status, int signal) { Context * ctx; ctx = context_find_from_pid(pid, 1); if (ctx == NULL) { ctx = find_pending(pid); if (ctx == NULL) { trace(LOG_EVENTS, "event: ctx not found, pid %d, exit status %d, term signal %d", pid, status, signal); } else { assert(ctx->ref_count == 0); ctx->ref_count = 1; if (EXT(ctx)->attach_callback != NULL) { if (status == 0) status = EINVAL; EXT(ctx)->attach_callback(status, ctx, EXT(ctx)->attach_data); } assert(list_is_empty(&ctx->children)); assert(ctx->parent == NULL); ctx->exited = 1; context_unlock(ctx); } } else { /* Note: ctx->exiting should be 1 here. However, PTRACE_EVENT_EXIT can be lost by PTRACE because of racing * between PTRACE_CONT (or PTRACE_SYSCALL) and SIGTRAP/PTRACE_EVENT_EXIT. So, ctx->exiting can be 0. */ if (EXT(ctx->parent)->pid == pid) ctx = ctx->parent; assert(EXT(ctx)->attach_callback == NULL); if (ctx->exited) { trace(LOG_EVENTS, "event: ctx %#lx, pid %d, exit status %d unexpected, stopped %d, exited %d", ctx, pid, status, ctx->stopped, ctx->exited); } else { trace(LOG_EVENTS, "event: ctx %#lx, pid %d, exit status %d, term signal %d", ctx, pid, status, signal); ctx->exiting = 1; if (ctx->stopped) send_context_started_event(ctx); if (!list_is_empty(&ctx->children)) { LINK * l = ctx->children.next; while (l != &ctx->children) { Context * c = cldl2ctxp(l); l = l->next; assert(c->parent == ctx); if (!c->exited) { c->exiting = 1; if (c->stopped) send_context_started_event(c); release_error_report(EXT(c)->regs_error); loc_free(EXT(c)->regs); EXT(c)->regs_error = NULL; EXT(c)->regs = NULL; send_context_exited_event(c); } } } release_error_report(EXT(ctx)->regs_error); loc_free(EXT(ctx)->regs); EXT(ctx)->regs_error = NULL; EXT(ctx)->regs = NULL; send_context_exited_event(ctx); } } }
static void event_pid_stopped(pid_t pid, int signal, int event, int syscall) { int stopped_by_exception = 0; Context * ctx = NULL; trace(LOG_EVENTS, "event: pid %d stopped, signal %d, event %s", pid, signal, event_name(event)); ctx = context_find_from_pid(pid, 1); if (ctx == NULL) { ctx = find_pending(pid); if (ctx != NULL) { Context * prs = ctx; assert(prs->ref_count == 0); ctx = create_context(pid2id(pid, pid)); EXT(ctx)->pid = pid; EXT(ctx)->regs = (REG_SET *)loc_alloc(sizeof(REG_SET)); ctx->pending_intercept = 1; ctx->mem = prs; ctx->parent = prs; ctx->big_endian = prs->big_endian; prs->ref_count++; list_add_last(&ctx->cldl, &prs->children); link_context(prs); link_context(ctx); send_context_created_event(prs); send_context_created_event(ctx); if (EXT(prs)->attach_callback) { EXT(prs)->attach_callback(0, prs, EXT(prs)->attach_data); EXT(prs)->attach_callback = NULL; EXT(prs)->attach_data = NULL; } } } if (ctx == NULL) return; assert(!ctx->exited); assert(!EXT(ctx)->attach_callback); if (signal != SIGSTOP && signal != SIGTRAP) { assert(signal < 32); ctx->pending_signals |= 1 << signal; if ((ctx->sig_dont_stop & (1 << signal)) == 0) { ctx->pending_intercept = 1; stopped_by_exception = 1; } } if (ctx->stopped) { send_context_changed_event(ctx); } else { ContextAddress pc0 = 0; ContextAddress pc1 = 0; assert(!EXT(ctx)->regs_dirty); EXT(ctx)->end_of_step = 0; EXT(ctx)->ptrace_event = event; ctx->signal = signal; ctx->stopped_by_bp = 0; ctx->stopped_by_exception = stopped_by_exception; ctx->stopped = 1; if (EXT(ctx)->regs_error) { release_error_report(EXT(ctx)->regs_error); EXT(ctx)->regs_error = NULL; } else { pc0 = get_regs_PC(ctx); } if (ptrace(PTRACE_GETREGS, EXT(ctx)->pid, 0, (int)EXT(ctx)->regs) < 0) { assert(errno != 0); if (errno == ESRCH) { /* Racing condition: somebody resumed this context while we are handling stop event. * * One possible cause: main thread has exited forcing children to exit too. * I beleive it is a bug in PTRACE implementation - PTRACE should delay exiting of * a context while it is stopped, but it does not, which causes a nasty racing. * * Workaround: Ignore current event, assume context is running. */ ctx->stopped = 0; return; } EXT(ctx)->regs_error = get_error_report(errno); trace(LOG_ALWAYS, "error: ptrace(PTRACE_GETREGS) failed; id %s, error %d %s", ctx->id, errno, errno_to_str(errno)); } else { pc1 = get_regs_PC(ctx); } trace(LOG_EVENTS, "event: pid %d stopped at PC = %#lx", pid, pc1); if (signal == SIGTRAP && event == 0 && !syscall) { size_t break_size = 0; get_break_instruction(ctx, &break_size); ctx->stopped_by_bp = !EXT(ctx)->regs_error && is_breakpoint_address(ctx, pc1 - break_size); EXT(ctx)->end_of_step = !ctx->stopped_by_bp && EXT(ctx)->pending_step; if (ctx->stopped_by_bp) set_regs_PC(ctx, pc1 - break_size); } EXT(ctx)->pending_step = 0; send_context_stopped_event(ctx); } }