XMFLOAT4 TransferFunction::operator()(int isoValue) { float alp = _a(isoValue) < 0 ? 0 : (_a(isoValue) > 1 ? 1 : _a(isoValue)); float red = _r(isoValue) < 0 ? 0 : (_r(isoValue) > 1 ? 1 : _r(isoValue)); float gre = _g(isoValue) < 0 ? 0 : (_g(isoValue) > 1 ? 1 : _g(isoValue)); float blu = _b(isoValue) < 0 ? 0 : (_b(isoValue) > 1 ? 1 : _b(isoValue)); return XMFLOAT4(red, gre, blu, alp); }
double _phiElec(int i, unifac_solution *s) { int j; double numer, denom = 0; numer = s->xi[i] * pow(_r(s->m[i]), 3./4.); for(j=0; j<s->nsolutes; j++) denom += s->xi[j] * pow(_r(s->m[j]), 3./4.); return numer/denom; }
void SymmAnisotropicElasticityTensor::form_r_matrix() { Real phi1 = _euler_angle[0] * (libMesh::pi / 180.0); Real phi = _euler_angle[1] * (libMesh::pi / 180.0); Real phi2 = _euler_angle[2] * (libMesh::pi / 180.0); Real cp1 = std::cos(phi1); Real cp2 = std::cos(phi2); Real cp = std::cos(phi); Real sp1 = std::sin(phi1); Real sp2 = std::sin(phi2); Real sp = std::sin(phi); _r(0, 0) = cp1 * cp2 - sp1 * sp2 * cp; _r(0, 1) = sp1 * cp2 + cp1 * sp2 * cp; _r(0, 2) = sp2 * sp; _r(1, 0) = -cp1 * sp2 - sp1 * cp2 * cp; _r(1, 1) = -sp1 * sp2 + cp1 * cp2 * cp; _r(1, 2) = cp2 * sp; _r(2, 0) = sp1 * sp; _r(2, 1) = -cp1 * sp; _r(2, 2) = cp; }
void SymmAnisotropicElasticityTensor::form_rotational_q_matrix() { for (int i = 0; i < 3; ++i) for (int j = 0; j < 3; ++j) for (int k = 0; k < 3; ++k) for (int l = 0; l < 3; ++l) _q(((i * 3) + k), ((j * 3) + l)) = _r(i, j) * _r(k, l); /*for (int p = 0; p < 9; ++p) for (int q = 0; q < 9; ++q) _qt(q,p) = _q(p,q);*/ }
/** * The L_i value is calculated from q, r, and z, where q and r are defined * above and z is the coordination number. Here, z is assumed to be equal to * ten. * \f[ * L_i = \frac{z}{2}(r_i - q_i) - (r_i -1) * \f] * @param molec Molecule to calculate the value for * @returns L_i */ double _L(unifac_molec molec) { double ri, qi; ri = _r(molec); qi = _q(molec); return Z/2*(ri - qi) - (ri - 1); }
void CRendererDX::Text( spCBaseFont _spFont, const std::string &_text, const Base::Math::CVector4 &_color, const Base::Math::CRect &_rect, uint32 _flags ) { ASSERT( _text != "" ); if( _spFont == NULL ) return; const fp4 w05 = (fp4)m_spDisplay->Width() * 0.5f; const fp4 h05 = (fp4)m_spDisplay->Height() * 0.5f; Base::Math::CRect _r( lerpMacro( -w05, w05, _rect.m_X0 ), lerpMacro( -h05, h05, _rect.m_Y0 ), lerpMacro( -w05, w05, _rect.m_X1 ), lerpMacro( -h05, h05, _rect.m_Y1 ) ); RECT r = { (LONG)_r.m_X0, (LONG)_r.m_Y0, (LONG)_r.m_X1, (LONG)_r.m_Y1, }; DWORD d3dFlags = DT_NOCLIP; if( _flags & CBaseFont::Bottom ) d3dFlags |= DT_BOTTOM; // bug if CBaseFont::Bottom == 0 because of check _flag & 0 != 0 if( _flags & CBaseFont::Top ) d3dFlags |= DT_TOP; if( _flags & CBaseFont::Center ) d3dFlags |= DT_CENTER; if( _flags & CBaseFont::Left ) d3dFlags |= DT_LEFT; if( _flags & CBaseFont::Right ) d3dFlags |= DT_RIGHT; if( _flags & CBaseFont::VCenter ) d3dFlags |= DT_VCENTER; if( _flags & CBaseFont::NoClip ) d3dFlags |= DT_NOCLIP; if( _flags & CBaseFont::ExpandTabs ) d3dFlags |= DT_EXPANDTABS; if( _flags & CBaseFont::WordBreak ) d3dFlags |= DT_WORDBREAK; DWORD d3dColor = D3DCOLOR_COLORVALUE( _color.m_X, _color.m_Y, _color.m_Z, _color.m_W ); spCFontDX spDXFont = _spFont; ID3DXFont *pDXFont = spDXFont->GetDXFont(); ASSERT( pDXFont ); m_pSprite->Begin( D3DXSPRITE_ALPHABLEND | D3DXSPRITE_SORT_TEXTURE | D3DXSPRITE_OBJECTSPACE | D3DXSPRITE_DO_NOT_ADDREF_TEXTURE ); pDXFont->DrawTextA( m_pSprite, (const char *)_text.c_str(), -1, &r, d3dFlags, d3dColor ); m_pSprite->End(); }
static void assRender(VSFrameRef *dst, VSFrameRef *alpha, const VSAPI *vsapi, ASS_Image *img) { uint8_t *planes[4]; int strides[4], p; for(p = 0; p < 4; p++) { VSFrameRef *fr = p == 3 ? alpha : dst; planes[p] = vsapi->getWritePtr(fr, p % 3); strides[p] = vsapi->getStride(fr, p % 3); memset(planes[p], 0, strides[p] * vsapi->getFrameHeight(fr, p % 3)); } while(img) { uint8_t *dstp[4], *alphap, *sp, color[4]; uint16_t outa; int x, y, k; if(img->w == 0 || img->h == 0) { img = img->next; continue; } color[0] = _r(img->color); color[1] = _g(img->color); color[2] = _b(img->color); color[3] = _a(img->color); dstp[0] = planes[0] + (strides[0] * img->dst_y) + img->dst_x; dstp[1] = planes[1] + (strides[1] * img->dst_y) + img->dst_x; dstp[2] = planes[2] + (strides[2] * img->dst_y) + img->dst_x; dstp[3] = planes[3] + (strides[3] * img->dst_y) + img->dst_x; alphap = dstp[3]; sp = img->bitmap; for(y = 0; y < img->h; y++) { for(x = 0; x < img->w; x++) { k = div255(sp[x] * color[3]); outa = k * 255 + (alphap[x] * (255 - k)); if(outa != 0) { dstp[0][x] = blend(k, color[0], alphap[x], dstp[0][x], outa); dstp[1][x] = blend(k, color[1], alphap[x], dstp[1][x], outa); dstp[2][x] = blend(k, color[2], alphap[x], dstp[2][x], outa); dstp[3][x] = div255(outa); } } dstp[0] += strides[0]; dstp[1] += strides[1]; dstp[2] += strides[2]; dstp[3] += strides[3]; alphap += strides[3]; sp += img->stride; } img = img->next; } }
static void blend_single(SDL_Surface * frame, ASS_Image *img) { int x, y; unsigned char opacity = 255 - _a(img->color); unsigned char r = _r(img->color); unsigned char g = _g(img->color); unsigned char b = _b(img->color); unsigned char *src; unsigned char *dst; src = img->bitmap; dst = frame->pixels; for (y = 0; y < img->h; ++y) { for (x = 0; x < img->w; ++x) { unsigned k = ((unsigned) src[x]) * opacity / 255; // possible endianness problems dst[x * 4] = (k * b + (255 - k) * dst[x * 4]) / 255; dst[x * 4 + 1] = (k * g + (255 - k) * dst[x * 4 + 1]) / 255; dst[x * 4 + 2] = (k * r + (255 - k) * dst[x * 4 + 2]) / 255; dst[x * 4 + 3] = k; } src += img->stride; dst += frame->pitch; } }
Z3_ast Z3_API Z3_algebraic_root(Z3_context c, Z3_ast a, unsigned k) { Z3_TRY; LOG_Z3_algebraic_root(c, a, k); RESET_ERROR_CODE(); CHECK_IS_ALGEBRAIC_X(a, 0); if (k % 2 == 0) { if ((is_rational(c, a) && get_rational(c, a).is_neg()) || (!is_rational(c, a) && am(c).is_neg(get_irrational(c, a)))) { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); } } algebraic_numbers::manager & _am = am(c); scoped_anum _r(_am); if (is_rational(c, a)) { scoped_anum av(_am); _am.set(av, get_rational(c, a).to_mpq()); _am.root(av, k, _r); } else { algebraic_numbers::anum const & av = get_irrational(c, a); _am.root(av, k, _r); } expr * r = au(c).mk_numeral(_r, false); mk_c(c)->save_ast_trail(r); RETURN_Z3(of_ast(r)); Z3_CATCH_RETURN(0); }
static void blend_single(image_t * frame, ASS_Image *img) { int x, y; unsigned char opacity = 255 - _a(img->color); unsigned char r = _r(img->color); unsigned char g = _g(img->color); unsigned char b = _b(img->color); unsigned char *src; unsigned char *dst; src = img->bitmap; dst = frame->buffer + img->dst_y * frame->stride + img->dst_x * 3; for (y = 0; y < img->h; ++y) { for (x = 0; x < img->w; ++x) { unsigned k = ((unsigned) src[x]) * opacity / 255; // possible endianness problems dst[x * 3] = (k * b + (255 - k) * dst[x * 3]) / 255; dst[x * 3 + 1] = (k * g + (255 - k) * dst[x * 3 + 1]) / 255; dst[x * 3 + 2] = (k * r + (255 - k) * dst[x * 3 + 2]) / 255; } src += img->stride; dst += frame->stride; } }
/// @brief Draw subtitles /// @param frame /// @param time /// @return /// void LibassSubtitlesProvider::DrawSubtitles(AegiVideoFrame &frame,double time) { // Set size ass_set_frame_size(ass_renderer, frame.w, frame.h); // Get frame ASS_Image* img = ass_render_frame(ass_renderer, ass_track, int(time * 1000), NULL); // libass actually returns several alpha-masked monochrome images. // Here, we loop through their linked list, get the colour of the current, and blend into the frame. // This is repeated for all of them. while (img) { // Get colours unsigned int opacity = 255 - ((unsigned int)_a(img->color)); unsigned int r = (unsigned int)_r(img->color); unsigned int g = (unsigned int)_g(img->color); unsigned int b = (unsigned int) _b(img->color); // Prepare copy int src_stride = img->stride; int dst_stride = frame.pitch; const unsigned char *src = img->bitmap; unsigned char *dst = frame.data; if (frame.flipped) { dst += dst_stride * (frame.h - 1); dst_stride *= -1; } dst += (img->dst_y * dst_stride + img->dst_x * 4); // Copy image to destination frame for (int y = 0; y < img->h; y++) { unsigned char *dstp = dst; for (int x = 0; x < img->w; ++x) { unsigned int k = ((unsigned)src[x]) * opacity / 255; unsigned int ck = 255 - k; *dstp = (k * b + ck * *dstp) / 255; ++dstp; *dstp = (k * g + ck * *dstp) / 255; ++dstp; *dstp = (k * r + ck * *dstp) / 255; ++dstp; ++dstp; } dst += dst_stride; src += src_stride; } // Next image img = img->next; } }
bool isSpriteContainPoint(Sprite *_sprite, Point _point, Point &_outPoint) { _outPoint = _sprite->convertToNodeSpace(_point); Size _s = _sprite->getContentSize(); Rect _r(0, 0, _s.width, _s.height); return _r.containsPoint(_outPoint); }
static int writeData(void* _call) { unsigned char r; unsigned char g; unsigned char b; unsigned char a; int x,y; int res = 0; unsigned char* dst; WriterFBCallData_t* call = (WriterFBCallData_t*) _call; fb_printf(100, "\n"); if (call == NULL) { fb_err("call data is NULL...\n"); return 0; } if (call->destination == NULL) { fb_err("file pointer < 0. ignoring ...\n"); return 0; } if (call->data != NULL) { unsigned int opacity = 255 - ((unsigned int)_a(call->color)); unsigned int r = (unsigned int)_r(call->color); unsigned int g = (unsigned int)_g(call->color); unsigned int b = (unsigned int) _b(call->color); int src_stride = call->Stride; int dst_stride = call->destStride; int dst_delta = dst_stride - call->Width*4; int x,y; const unsigned char *src = call->data; unsigned char *dst = call->destination + (call->y * dst_stride + call->x * 4); //uint32_t *dst = call->destination + call->y * dst_stride + call->x; unsigned int k,ck,t; static uint32_t last_color = 0, colortable[256]; if (last_color != call->color) { // call->color is rgba, our spark frame buffer is argb uint32_t c = call->color >> 8, a = 255 - (call->color & 0xff); int i; for (i = 0; i < 256; i++) { uint32_t k = (a * i) >> 8; colortable[i] = k ? (c | (k << 24)) : 0; } last_color = call->color; }
// render 1 ass image into a 32bit QImage with alpha channel. //use dstX, dstY instead of img->dst_x/y because image size is small then ass renderer size void RenderASS(QImage *image, const SubImage& img, int dstX, int dstY) { const quint8 a = 255 - _a(img.color); if (a == 0) return; const quint8 r = _r(img.color); const quint8 g = _g(img.color); const quint8 b = _b(img.color); const quint8 *src = (const quint8*)img.data.constData(); // use QRgb to avoid endian issue QRgb *dst = (QRgb*)image->constBits() + dstY * image->width() + dstX; // k*src+(1-k)*dst for (int y = 0; y < img.height(); ++y) { for (int x = 0; x < img.width(); ++x) { const unsigned k = ((unsigned) src[x])*a/255; #if USE_QRGBA const unsigned A = qAlpha(dst[x]); #else quint8 *c = (quint8*)(&dst[x]); const unsigned A = ARGB32_A(c); #endif if (A == 0) { // dst color can be ignored #if USE_QRGBA dst[x] = qRgba(r, g, b, k); #else ARGB32_SET(c, r, g, b, k); #endif //USE_QRGBA } else if (k == 0) { //no change //dst[x] = qRgba(qRed(dst[x])), qGreen(dst[x]), qBlue(dst[x]), qAlpha(dst[x])) == dst[x]; } else if (k == 255) { #if USE_QRGBA dst[x] = qRgba(r, g, b, k); #else ARGB32_SET(c, r, g, b, k); #endif //USE_QRGBA } else { // c=k*dc/255=k*dc/256 * (1-1/256), -1<err(c) = k*dc/256^2<1, -1 is bad! #if USE_QRGBA // no need to &0xff because always be 0~255 dst[x] += qRgba2(k*(r-qRed(dst[x]))/255, k*(g-qGreen(dst[x]))/255, k*(b-qBlue(dst[x]))/255, k*(a-A)/255); #else const unsigned R = ARGB32_R(c); const unsigned G = ARGB32_G(c); const unsigned B = ARGB32_B(c); ARGB32_ADD(c, r == R ? 0 : k*(r-R)/255, g == G ? 0 : k*(g-G)/255, b == B ? 0 : k*(b-B)/255, a == A ? 0 : k*(a-A)/255); #endif } } src += img.stride(); dst += image->width(); } }
// C[i] = C'[i] = (k*c[i]+(255-k)*C[i])/255 = C[i] + k*(c[i]-C[i])/255, min(c[i],C[i]) <= C'[i] <= max(c[i],C[i]) void SubtitleProcessorLibASS::renderASS32(QImage *image, ASS_Image *img, int dstX, int dstY) { const quint8 a = 255 - _a(img->color); if (a == 0) return; const quint8 r = _r(img->color); const quint8 g = _g(img->color); const quint8 b = _b(img->color); quint8 *src = img->bitmap; // use QRgb to avoid endian issue QRgb *dst = (QRgb*)image->bits() + dstY * image->width() + dstX; for (int y = 0; y < img->h; ++y) { for (int x = 0; x < img->w; ++x) { const unsigned k = ((unsigned) src[x])*a/255; #if USE_QRGBA const unsigned A = qAlpha(dst[x]); #else quint8 *c = (quint8*)(&dst[x]); const unsigned A = ARGB32_A(c); #endif if (A == 0) { // dst color can be ignored #if USE_QRGBA dst[x] = qRgba(r, g, b, k); #else ARGB32_SET(c, r, g, b, k); #endif //USE_QRGBA } else if (k == 0) { //no change //dst[x] = qRgba(qRed(dst[x])), qGreen(dst[x]), qBlue(dst[x]), qAlpha(dst[x])) == dst[x]; } else if (k == 255) { #if USE_QRGBA dst[x] = qRgba(r, g, b, k); #else ARGB32_SET(c, r, g, b, k); #endif //USE_QRGBA } else { #if USE_QRGBA // no need to &0xff because always be 0~255 dst[x] += qRgba2(k*(r-qRed(dst[x]))/255, k*(g-qGreen(dst[x]))/255, k*(b-qBlue(dst[x]))/255, k*(a-A)/255); #else const unsigned R = ARGB32_R(c); const unsigned G = ARGB32_G(c); const unsigned B = ARGB32_B(c); ARGB32_ADD(c, r == R ? 0 : k*(r-R)/255, g == G ? 0 : k*(g-G)/255, b == B ? 0 : k*(b-B)/255, a == A ? 0 : k*(a-A)/255); #endif } } src += img->stride; dst += image->width(); } }
void readers::updateReaders(){ for (int a = ui.tableWidget_readers->rowCount(); a >= 0; a--){ ui.tableWidget_readers->removeRow(a); } QSqlQuery _r("select readers.id, readers.fam, readers.ima, readers.otc, readers.date_r, readers.num, readers.phone, " "readers.address, readers.doc from readers order by readers.fam "); int row = 0; while (_r.next()){ ui.tableWidget_readers->insertRow(row); for (int col = 0; col < 9; col++){ QTableWidgetItem *item = new QTableWidgetItem(_r.value(col).toString()); ui.tableWidget_readers->setItem(row, col, item); } row++; } }
void SymmAnisotropicElasticityTensor::show_r_matrix() { printf("\nSymmAnisotropicElasticityTensor::show_r_matrix() Euler angles are (%f, %f, %f)\n", _euler_angle[0], _euler_angle[1], _euler_angle[2]); for (int j = 0; j < 3; ++j) { printf(" "); for (int i = 0; i < 3; ++i) { printf("%8.4f ", _r(i, j)); } printf("\n"); } }
Z3_ast_vector Z3_API Z3_polynomial_subresultants(Z3_context c, Z3_ast p, Z3_ast q, Z3_ast x) { Z3_TRY; LOG_Z3_polynomial_subresultants(c, p, q, x); RESET_ERROR_CODE(); polynomial::manager & pm = mk_c(c)->pm(); polynomial_ref _p(pm), _q(pm); polynomial::scoped_numeral d(pm.m()); default_expr2polynomial converter(mk_c(c)->m(), pm); if (!converter.to_polynomial(to_expr(p), _p, d) || !converter.to_polynomial(to_expr(q), _q, d)) { SET_ERROR_CODE(Z3_INVALID_ARG); return 0; } Z3_ast_vector_ref* result = alloc(Z3_ast_vector_ref, mk_c(c)->m()); mk_c(c)->save_object(result); if (converter.is_var(to_expr(x))) { expr2var const & mapping = converter.get_mapping(); unsigned v_x = mapping.to_var(to_expr(x)); polynomial_ref_vector rs(pm); polynomial_ref r(pm); expr_ref _r(mk_c(c)->m()); { cancel_eh<polynomial::manager> eh(pm); api::context::set_interruptable si(*(mk_c(c)), eh); scoped_timer timer(mk_c(c)->params().m_timeout, &eh); pm.psc_chain(_p, _q, v_x, rs); } for (unsigned i = 0; i < rs.size(); i++) { r = rs.get(i); converter.to_expr(r, true, _r); result->m_ast_vector.push_back(_r); } } RETURN_Z3(of_ast_vector(result)); Z3_CATCH_RETURN(0); }
static int writeData(void* _call) { unsigned char r; unsigned char g; unsigned char b; unsigned char a; int x,y; int res = 0; unsigned char* dst; WriterFBCallData_t* call = (WriterFBCallData_t*) _call; fb_printf(100, "\n"); if (call == NULL) { fb_err("call data is NULL...\n"); return 0; } if (call->destination == NULL) { fb_err("file pointer < 0. ignoring ...\n"); return 0; } if (call->data != NULL) { unsigned int opacity = 255 - ((unsigned int)_a(call->color)); unsigned int r = (unsigned int)_r(call->color); unsigned int g = (unsigned int)_g(call->color); unsigned int b = (unsigned int) _b(call->color); int src_stride = call->Stride; int dst_stride = call->destStride; int dst_delta = dst_stride - call->Width*4; int x,y; const unsigned char *src = call->data; unsigned char *dst = call->destination + (call->y * dst_stride + call->x * 4); unsigned int k,ck,t; fb_printf(100, "x %d\n", call->x); fb_printf(100, "y %d\n", call->y); fb_printf(100, "width %d\n", call->Width); fb_printf(100, "height %d\n", call->Height); fb_printf(100, "stride %d\n", call->Stride); fb_printf(100, "color %d\n", call->color); fb_printf(100, "data %p\n", call->data); fb_printf(100, "dest %p\n", call->destination); fb_printf(100, "dest.stride %d\n", call->destStride); fb_printf(100, "r 0x%hhx, g 0x%hhx, b 0x%hhx, a 0x%hhx, opacity %d\n", r, g, b, a, opacity); for (y=0;y<call->Height;y++) { for (x = 0; x < call->Width; x++) { k = ((unsigned)src[x]) * opacity / 255; ck = 255 - k; t = *dst; *dst++ = (k*b + ck*t) / 255; t = *dst; *dst++ = (k*g + ck*t) / 255; t = *dst; *dst++ = (k*r + ck*t) / 255; *dst++ = 0; } dst += dst_delta; src += src_stride; } } else { for (y = 0; y < call->Height; y++) memset(call->destination + ((call->y + y) * call->destStride) + call->x * 4, 0, call->Width * 4); } fb_printf(100, "< %d\n", res); return res; }
// distance of the centers of spheres T distance(const Sphere& rhs) const { // move two spheres so that the center of (*this) comes to the origin Sphere _r(rhs.x - x, rhs.y - y, rhs.z - z, rhs.r); return Vector3D<T>(_r.x, _r.y, _r.z).abs(); }
/* Safe forking/cloning * * This function takes over the PRE fase of a child process' fork * syscall. It then forks the child in a controlled manor ensuring * tracy will be able to trace the forked process. * This function returns the pid of the new child in new_child upon success. * * Upon error the return value will be -1 and errno will be set appropriately. * * FIXME: This function memleaks a page upon failure in the child atm. * TODO: This function needs a lot more error handling than it contains now. * FIXME: Due to the PTRACE_CHECK macro's if a ptrace fails, we will not * restore the original signal handler for SIGUSR1. */ int tracy_safe_fork(struct tracy_child *c, pid_t *new_child) { tracy_child_addr_t mmap_ret; int status; long ip, orig_syscall, orig_trampy_pid_reg; struct TRACY_REGS_NAME args, args_ret; const long page_size = sysconf(_SC_PAGESIZE); pid_t child_pid; struct sigaction act, old_sigusr1, old_sigchld; sigset_t set, old_set; struct timespec timeout; siginfo_t info; int is_vforking = 0; child_pid = -1; tracy_debug_current(c); /* puts("SAFE_FORKING!"); */ /* First let's allocate a page in the child which we shall use * to write a piece of forkcode (see trampy.c) to. */ tracy_mmap(c, &mmap_ret, NULL, page_size, PROT_READ | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0 ); /* I know this is FUBAR, but bear with me * * Check for an error value in the return code/address. */ if (mmap_ret < ((tracy_child_addr_t)NULL) && mmap_ret > ((tracy_child_addr_t)-4096)) { errno = -(long)mmap_ret; perror("tracy_mmap"); return -1; } /* printf("mmap addr: %p\n", (void*)mmap_ret); */ /* XXX - Debug printf("trampy_get_safe_entry() = %p\ntrampy_get_code_size() = %d\n", trampy_get_safe_entry(), trampy_get_code_size()); */ /* Write the piece of code to the child process */ if (tracy_write_mem(c, (void*) mmap_ret, trampy_get_safe_entry(), trampy_get_code_size()) < 0) { perror("tracy_write_mem"); return -1; } /* Fetch the registers to store the original forking syscall and more importantly * the instruction pointer. */ PTRACE_CHECK(PTRACE_GETREGS, c->pid, 0, &args, -1); /* Deny so we can set the IP on the denied post and do our own fork in a * controlled environment */ tracy_deny_syscall(c); c->denied_nr = 0; PTRACE_CHECK(PTRACE_SYSCALL, c->pid, 0, 0, -1); /* puts("DENIED, in PRE"); */ waitpid(c->pid, &status, __WALL); /* puts("AFTER DENIED, entered POST"); */ /* Okay, the child is now in POST syscall mode, and it has * just executed a bogus syscall (getpid) inserted by deny syscall. * * Setup a fork syscall and point the processor to the injected code. */ /* * XXX: We do not have to modify the syscall NR since we use this function * for fork, clone and vfork. args.TRACY_SYSCALL_REGISTER = __NR_fork; args.TRACY_SYSCALL_N = __NR_fork; */ orig_syscall = args.TRACY_SYSCALL_REGISTER; orig_trampy_pid_reg = args.TRAMPY_PID_REG; printf(_r("Safe forking syscall")); #if 0 /* TODO: Fix for ABI */ printf(_r("Safe forking syscall:")" "_g("%s")"\n", get_syscall_name(args.TRACY_SYSCALL_REGISTER)); #endif /* Check if this is a vfork-type syscall */ if (orig_syscall == __NR_vfork) is_vforking = 1; /* Clone can also cause vfork behaviour */ #pragma message "getreg(&args, 0, 0) is abi dependent and wrong" if (orig_syscall == __NR_clone && get_reg(&args, 0, 0) & CLONE_VFORK) { puts(_b("clone with CLONE_VFORK detected, treating as vfork call")); is_vforking = 1; } /* XXX: TODO: Should we place an ARM PTRACE_SET_SYSCALL here? */ /* XXX: The IP we store here is the IP in the PRE phase of the parent process. * At that moment the IP points to the instruction following de syscall. */ ip = args.TRACY_IP_REG; args.TRACY_IP_REG = (long)mmap_ret; /* printf(_b("Pointer data @ IP 0x%lx: 0x%lx")"\n", ip, ptrace(PTRACE_PEEKDATA, c->pid, ip, NULL)); printf(_b("Pointer data @ IP-4 0x%lx: 0x%lx")"\n", ip - 4, ptrace(PTRACE_PEEKDATA, c->pid, ip - 4, NULL)); */ PTRACE_CHECK(PTRACE_SETREGS, c->pid, 0, &args, -1); /* printf("The IP was changed from %p to %p\n", (void*)ip, (void*)mmap_ret); puts("POST, Entering PRE"); */ PTRACE_CHECK(PTRACE_SYSCALL, c->pid, 0, 0, -1); waitpid(c->pid, &status, __WALL); /* At this moment the child is in PRE mode in the trampy code, * trying to execute a sched_yield, which we shall now make * into a fork syscall. */ PTRACE_CHECK(PTRACE_GETREGS, c->pid, 0, &args_ret, -1); /* printf("The IP is now %p\n", (void*)args_ret.TRACY_IP_REG); printf("Modifying syscall back to fork\n"); */ /* TODO: Replace the following with a single call to * tracy_modify_syscall(). */ args_ret.TRACY_SYSCALL_REGISTER = orig_syscall; args_ret.TRACY_SYSCALL_N = orig_syscall; /* This stores our pid in a specific register, which will then be used by * the new child to inform us of its existence. */ args_ret.TRAMPY_PID_REG = getpid(); /* On ARM the syscall number is not included in any register, so we have * this special ptrace option to modify the syscall */ #ifdef __arm__ PTRACE_CHECK(PTRACE_SET_SYSCALL, c->pid, 0, (void*)orig_syscall, -1); #endif PTRACE_CHECK(PTRACE_SETREGS, c->pid, 0, &args_ret, -1); /* puts("PRE, Entering POST"); */ /* Setup the blocking of signals to atomically wait for them after ptrace */ sigemptyset(&set); sigaddset(&set, SIGUSR1); sigaddset(&set, SIGCHLD); pthread_sigmask(SIG_BLOCK, &set, &old_set); /* Finally before we execute an actual fork syscall * setup the SIGUSR1 handler which is used by trampy to * inform us of vforking children */ act.sa_sigaction = _tracer_fork_signal_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; sigaction(SIGUSR1, &act, &old_sigusr1); sigaction(SIGCHLD, &act, &old_sigchld); /* Now execute the actual fork. * * Afterwards the parent will immediately come to a halt * while the child will wait for us to attach. See 'trampy.c' * for more details. */ PTRACE_CHECK(PTRACE_SYSCALL, c->pid, 0, 0, -1); /* Now wait for either SIGCHLD from the forker, * or SIGUSR1 from the forkee */ /*sigsuspend(&set);*/ /*pause();*/ /*sigwait(&set);*/ /* XXX: The manpage states all threads within the current process must block * aforementioned signals, so there might be some trouble caused by using tracy * within a multithreaded larger whole. If not all threads block these signals * some thread might still handle them before we get to call sigwaitinfo which * causes lock-up of this thread in the worst case or otherwise a race condition * wherein we never restore the child or the parent in case of vfork(). */ while (1) { sigwaitinfo(&set, &info); /* In case of SIGCHLD the parent or another process might've stopped */ if (info.si_signo == SIGCHLD && info.si_pid == c->pid) { /* The parent has stopped (completed its syscall), in case of vfork * this means the vfork failed. If it didn't something that shouldn't * happen occurred. */ if (is_vforking) { /* FIXME: There must be a more elegant way to handle failure, * which we currently don't do anyway so go.. go.. go.. */ printf(_r("tracy: During vfork(), failure in parent.")"\n"); child_pid = -1; break; } else { printf(_b("tracy: During fork(), parent returned first.")"\n"); break; } } /* This is the new child */ if (info.si_signo == SIGUSR1) { printf(_b("Handling SIGUSR1 from process %d, completing safe-fork") "\n", info.si_pid); /* If we're vforking the parent is now marked frozen */ if (is_vforking) { c->frozen_by_vfork = 1; c->orig_trampy_pid_reg = orig_trampy_pid_reg; c->orig_pc = ip; c->orig_return_code = info.si_pid; } /* Attach to the new child */ /*PTRACE_CHECK(PTRACE_ATTACH, info.si_pid, 0, 0, -1);*/ child_pid = info.si_pid; /* Return PID to caller if they're interested. */ /* XXX: Assignment to child_pid rarely happens, collapse this * line with th other somewhere useful. */ if (new_child) *new_child = child_pid; break; } } /* The trampy register is now restored to the original value */ args_ret.TRAMPY_PID_REG = orig_trampy_pid_reg; /* If we're vforking there is no point in resuming the parent because * it is frozen, unless the vfork failed. */ if (!is_vforking || child_pid == -1) { waitpid(c->pid, &status, __WALL); PTRACE_CHECK(PTRACE_GETREGS, c->pid, 0, &args_ret, -1); /* printf("The IP is now %p\n", (void*)args_ret.TRACY_IP_REG); puts("POST"); */ /* FIXME: We don't check if the fork failed * which we really should since there is no point in * attaching to a failed fork. */ child_pid = args_ret.TRACY_RETURN_CODE; /* Return PID to caller if they're interested. */ if (new_child) *new_child = child_pid; printf("Fork return value: %d\n", child_pid); /* Now point the parent process after the original fork * syscall instruction. */ args_ret.TRACY_IP_REG = ip; args_ret.TRACY_RETURN_CODE = child_pid; PTRACE_CHECK(PTRACE_SETREGS, c->pid, 0, &args_ret, -1); printf("Return code set to %d\n", child_pid); c->pre_syscall = 0; /* TODO Handle possible kill signal from child that might be waiting * in the singal set */ } /* End of non-vfork block */ /* Attach to the new child */ printf("Attaching to %d...\n", child_pid); /* Ptrace guarantees PRE state (? XXX TODO FIXME)*/ PTRACE_CHECK(PTRACE_ATTACH, child_pid, 0, 0, -1); if (waitpid(child_pid, &status, __WALL) == -1) { perror("Failure waiting for new child"); } /* if (ptrace(PTRACE_SETREGS, child_pid, 0, &args)) perror("SETREGS"); */ /* Restore the new child to its original position */ args.TRACY_IP_REG = ip; args.TRACY_RETURN_CODE = 0; /* Retrieve stack pointer first. * * clone can modify the stack pointer, so the stack pointer * needs to be left untouched. */ PTRACE_CHECK(PTRACE_GETREGS, child_pid, 0, &args_ret, -1); args.TRACY_STACK_POINTER = args_ret.TRACY_STACK_POINTER; /* Now update child registers */ PTRACE_CHECK(PTRACE_SETREGS, child_pid, 0, &args, -1); /* Set enhanced syscall tracing */ PTRACE_CHECK(PTRACE_SETOPTIONS, child_pid, 0, PTRACE_O_TRACESYSGOOD, -1); /* Continue the new child */ /* PTRACE_CHECK(PTRACE_SYSCALL, child_pid, 0, 0, -1); */ /* Poll for any remaining SIGUSR1 so this cannot kill us in the * original process signal mode. */ timeout.tv_sec = 0; timeout.tv_nsec = 0; sigdelset(&set, SIGCHLD); sigtimedwait(&set, &info, &timeout); /* Restore the original signal handlers */ sigaction(SIGUSR1, &old_sigusr1, NULL); sigaction(SIGCHLD, &old_sigchld, NULL); /* Restore signal mask settings */ pthread_sigmask(SIG_SETMASK, &old_set, NULL); /* TODO: We should now munmap the pages in both the parent and the child. * Unless ofc. we created a thread which shares VM in which case we should * munmap only once. */ return 0; }