Example #1
0
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);
}
Example #2
0
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);
}
Example #3
0
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;
}
Example #4
0
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;
	}
}
Example #5
0
/*
 * 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);
}
Example #6
0
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);
}
Example #7
0
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);
    }
}
Example #8
0
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);
        }
    }
}
Example #9
0
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);
    }
}