File agent/ninedogs.c changed (mode: 100644) (index 4b3b3ea..3008734) |
... |
... |
static void my_trace_put64(unsigned char *buf, unsigned int *i, const uint64_t v |
226 |
226 |
|
|
227 |
227 |
static void my_trace_put_double(unsigned char *buf, unsigned int *i, const double v) |
static void my_trace_put_double(unsigned char *buf, unsigned int *i, const double v) |
228 |
228 |
{ |
{ |
229 |
|
uint64_t u = htobe64(v); |
|
230 |
|
memcpy(buf + *i, &u, 8); *i = *i + 8; |
|
|
229 |
|
uint64_t u; |
|
230 |
|
memcpy(&u, &v, 8); |
|
231 |
|
my_trace_put64(buf, i, u); |
231 |
232 |
} |
} |
232 |
233 |
|
|
233 |
234 |
static void my_trace_put_bool(unsigned char *buf, unsigned int *i, const char v) |
static void my_trace_put_bool(unsigned char *buf, unsigned int *i, const char v) |
|
... |
... |
static unsigned int my_trace_encode(unsigned char *buf, |
647 |
648 |
my_trace_put64(buf, &i, (uint64_t) q->dbh); |
my_trace_put64(buf, &i, (uint64_t) q->dbh); |
648 |
649 |
my_trace_put16(buf, &i, q->q_len); |
my_trace_put16(buf, &i, q->q_len); |
649 |
650 |
my_trace_put(buf, &i, q->q, q->q_len); |
my_trace_put(buf, &i, q->q, q->q_len); |
650 |
|
if (type == 'r') |
|
|
651 |
|
if (type == 'r') { |
651 |
652 |
my_trace_put64(buf, &i, (uint64_t) q->res); |
my_trace_put64(buf, &i, (uint64_t) q->res); |
|
653 |
|
my_trace_put64(buf, &i, q->num); |
|
654 |
|
my_trace_put64(buf, &i, q->aff); |
|
655 |
|
} |
652 |
656 |
} else if (strcmp(func, "mysqli_real_connect") == 0) { |
} else if (strcmp(func, "mysqli_real_connect") == 0) { |
653 |
657 |
struct conn *c = va_arg(va, struct conn *); |
struct conn *c = va_arg(va, struct conn *); |
654 |
658 |
my_trace_put64(buf, &i, (uint64_t) c->dbh); |
my_trace_put64(buf, &i, (uint64_t) c->dbh); |
|
... |
... |
static unsigned int my_trace_encode(unsigned char *buf, |
657 |
661 |
my_trace_put32(buf, &i, c->flags); |
my_trace_put32(buf, &i, c->flags); |
658 |
662 |
if (type == 'r') |
if (type == 'r') |
659 |
663 |
my_trace_put_bool(buf, &i, c->ret); |
my_trace_put_bool(buf, &i, c->ret); |
|
664 |
|
} else if (strcmp(func, "mysqli_stmt_bind_param") == 0) { |
|
665 |
|
struct nd_db_bind *b = va_arg(va, struct nd_db_bind *); |
|
666 |
|
my_trace_put64(buf, &i, (uint64_t) b->stmt); |
|
667 |
|
my_trace_put16(buf, &i, (uint16_t) b->types_len); |
|
668 |
|
my_trace_put(buf, &i, b->types, b->types_len); |
|
669 |
|
if (type == 'r') |
|
670 |
|
my_trace_put_bool(buf, &i, b->ret); |
660 |
671 |
} else if (strcmp(func, "mysqli_stmt_execute") == 0) { |
} else if (strcmp(func, "mysqli_stmt_execute") == 0) { |
661 |
|
struct execute *e = va_arg(va, struct execute *); |
|
|
672 |
|
struct nd_db_execute *e = va_arg(va, struct nd_db_execute *); |
662 |
673 |
my_trace_put64(buf, &i, (uint64_t) e->stmt); |
my_trace_put64(buf, &i, (uint64_t) e->stmt); |
663 |
674 |
if (type == 'c') { |
if (type == 'c') { |
664 |
675 |
my_trace_put16(buf, &i, e->params.len); |
my_trace_put16(buf, &i, e->params.len); |
|
... |
... |
static unsigned int my_trace_encode(unsigned char *buf, |
675 |
686 |
} |
} |
676 |
687 |
} |
} |
677 |
688 |
} |
} |
678 |
|
if (type == 'r') |
|
|
689 |
|
if (type == 'r') { |
679 |
690 |
my_trace_put_bool(buf, &i, e->ret); |
my_trace_put_bool(buf, &i, e->ret); |
|
691 |
|
if (e->ret == 1) { |
|
692 |
|
my_trace_put64(buf, &i, e->num); |
|
693 |
|
my_trace_put64(buf, &i, e->aff); |
|
694 |
|
} |
|
695 |
|
} |
680 |
696 |
} else if (strcmp(func, "mysqli_stmt_prepare") == 0) { |
} else if (strcmp(func, "mysqli_stmt_prepare") == 0) { |
681 |
697 |
struct prepare *p = va_arg(va, struct prepare *); |
struct prepare *p = va_arg(va, struct prepare *); |
682 |
698 |
my_trace_put64(buf, &i, (uint64_t) p->stmt); |
my_trace_put64(buf, &i, (uint64_t) p->stmt); |
File agent/php.c changed (mode: 100644) (index 547b340..c52cd55) |
... |
... |
static void zend_array_to_params_array(struct params_array *p, struct zend_array |
353 |
353 |
xlog(101, " para: bs=%p h=%lu key=[%p] type %s: val: %s\n", |
xlog(101, " para: bs=%p h=%lu key=[%p] type %s: val: %s\n", |
354 |
354 |
bs, bs->h, zs, php_get_type(_z), php_get_value(_z)); |
bs, bs->h, zs, php_get_type(_z), php_get_value(_z)); |
355 |
355 |
|
|
356 |
|
if (_z->u1.v.type == 4) { |
|
|
356 |
|
if (_z->u1.v.type == 1) { |
|
357 |
|
p->list[i].type = ND_PARAMS_TYPE_NULL; |
|
358 |
|
} else if (_z->u1.v.type == 2) { |
|
359 |
|
p->list[i].type = ND_PARAMS_TYPE_STRING; |
|
360 |
|
p->list[i].str = "false"; |
|
361 |
|
p->list[i].length = 5; |
|
362 |
|
} else if (_z->u1.v.type == 3) { |
|
363 |
|
p->list[i].type = ND_PARAMS_TYPE_STRING; |
|
364 |
|
p->list[i].str = "true"; |
|
365 |
|
p->list[i].length = 4; |
|
366 |
|
} else if (_z->u1.v.type == 4) { |
357 |
367 |
p->list[i].type = ND_PARAMS_TYPE_LONG; |
p->list[i].type = ND_PARAMS_TYPE_LONG; |
358 |
368 |
p->list[i].l = _z->value.lval; |
p->list[i].l = _z->value.lval; |
359 |
369 |
} else if (_z->u1.v.type == 5) { |
} else if (_z->u1.v.type == 5) { |
|
... |
... |
static void zend_array_to_params_array(struct params_array *p, struct zend_array |
364 |
374 |
struct zend_string *zs = _z->value.str; |
struct zend_string *zs = _z->value.str; |
365 |
375 |
p->list[i].str = zs->val; |
p->list[i].str = zs->val; |
366 |
376 |
p->list[i].length = zs->len; |
p->list[i].length = zs->len; |
|
377 |
|
} else { |
|
378 |
|
p->list[i].type = ND_PARAMS_TYPE_NULL; |
|
379 |
|
xlog(1, " I do not how to encode this type!\n"); |
367 |
380 |
} |
} |
368 |
381 |
|
|
369 |
382 |
i++; |
i++; |
|
... |
... |
static void zend_array_to_params_array(struct params_array *p, struct zend_array |
372 |
385 |
} |
} |
373 |
386 |
} |
} |
374 |
387 |
|
|
375 |
|
void *(*old_pg_last_error)(struct zend_execute_data *, struct zval *); |
|
|
388 |
|
static void php_set_para(struct zend_execute_data *e, const unsigned int i, |
|
389 |
|
const struct zval *para) |
|
390 |
|
{ |
|
391 |
|
unsigned int s; |
|
392 |
|
struct zval *dst; |
|
393 |
|
|
|
394 |
|
s = (sizeof(struct zend_execute_data) + sizeof(struct zval) - 1) / sizeof(struct zval); |
|
395 |
|
dst = (struct zval *) e + s + i; |
|
396 |
|
memcpy(dst, para, sizeof(struct zval)); |
|
397 |
|
} |
|
398 |
|
|
|
399 |
|
|
|
400 |
|
static void *(*old_pg_last_error)(struct zend_execute_data *, struct zval *); |
376 |
401 |
static void *my_pg_last_error(struct zend_execute_data *e, struct zval *retv) |
static void *my_pg_last_error(struct zend_execute_data *e, struct zval *retv) |
377 |
402 |
{ |
{ |
378 |
403 |
void *ret; |
void *ret; |
|
... |
... |
static void *my_pg_last_error(struct zend_execute_data *e, struct zval *retv) |
385 |
410 |
ret = old_pg_last_error(e, retv); |
ret = old_pg_last_error(e, retv); |
386 |
411 |
if (!retv) |
if (!retv) |
387 |
412 |
return ret; |
return ret; |
388 |
|
|
|
389 |
413 |
//php_zval_dump(" retv: ", retv); |
//php_zval_dump(" retv: ", retv); |
390 |
414 |
|
|
391 |
415 |
return ret; |
return ret; |
392 |
416 |
} |
} |
393 |
417 |
|
|
394 |
|
void *(*old_pg_close)(struct zend_execute_data *, struct zval *); |
|
|
418 |
|
static void *(*old_pg_close)(struct zend_execute_data *, struct zval *); |
395 |
419 |
static void *my_pg_close(struct zend_execute_data *e, struct zval *retv) |
static void *my_pg_close(struct zend_execute_data *e, struct zval *retv) |
396 |
420 |
{ |
{ |
397 |
421 |
void *ret; |
void *ret; |
|
... |
... |
static void *my_pg_close(struct zend_execute_data *e, struct zval *retv) |
419 |
443 |
return ret; |
return ret; |
420 |
444 |
} |
} |
421 |
445 |
|
|
422 |
|
void *(*old_pg_connect)(struct zend_execute_data *, struct zval *); |
|
|
446 |
|
static void *(*old_pg_connect)(struct zend_execute_data *, struct zval *); |
423 |
447 |
static void *my_pg_connect(struct zend_execute_data *e, struct zval *retv) |
static void *my_pg_connect(struct zend_execute_data *e, struct zval *retv) |
424 |
448 |
{ |
{ |
425 |
449 |
void *ret; |
void *ret; |
|
... |
... |
static void *my_pg_connect(struct zend_execute_data *e, struct zval *retv) |
461 |
485 |
return ret; |
return ret; |
462 |
486 |
} |
} |
463 |
487 |
|
|
464 |
|
void *(*old_pg_pconnect)(struct zend_execute_data *, struct zval *); |
|
|
488 |
|
static void *(*old_pg_pconnect)(struct zend_execute_data *, struct zval *); |
465 |
489 |
static void *my_pg_pconnect(struct zend_execute_data *e, struct zval *retv) |
static void *my_pg_pconnect(struct zend_execute_data *e, struct zval *retv) |
466 |
490 |
{ |
{ |
467 |
491 |
void *ret; |
void *ret; |
|
... |
... |
static void *my_pg_pconnect(struct zend_execute_data *e, struct zval *retv) |
501 |
525 |
return ret; |
return ret; |
502 |
526 |
} |
} |
503 |
527 |
|
|
504 |
|
void *(*old_pg_affected_rows)(struct zend_execute_data *, struct zval *); |
|
|
528 |
|
static void *(*old_pg_affected_rows)(struct zend_execute_data *, struct zval *); |
505 |
529 |
|
|
506 |
|
void *(*old_pg_free_result)(struct zend_execute_data *, struct zval *); |
|
|
530 |
|
static void *(*old_pg_free_result)(struct zend_execute_data *, struct zval *); |
507 |
531 |
static void *my_pg_free_result(struct zend_execute_data *e, struct zval *retv) |
static void *my_pg_free_result(struct zend_execute_data *e, struct zval *retv) |
508 |
532 |
{ |
{ |
509 |
533 |
void *ret; |
void *ret; |
|
... |
... |
static void *my_pg_free_result(struct zend_execute_data *e, struct zval *retv) |
538 |
562 |
return ret; |
return ret; |
539 |
563 |
} |
} |
540 |
564 |
|
|
541 |
|
void *(*old_pg_num_rows)(struct zend_execute_data *, struct zval *); |
|
|
565 |
|
static void *(*old_pg_num_rows)(struct zend_execute_data *, struct zval *); |
542 |
566 |
static void *my_pg_num_rows(struct zend_execute_data *e, struct zval *retv) |
static void *my_pg_num_rows(struct zend_execute_data *e, struct zval *retv) |
543 |
567 |
{ |
{ |
544 |
568 |
void *ret; |
void *ret; |
|
... |
... |
static void *my_pg_num_rows(struct zend_execute_data *e, struct zval *retv) |
557 |
581 |
return ret; |
return ret; |
558 |
582 |
} |
} |
559 |
583 |
|
|
560 |
|
static void php_set_para(struct zend_execute_data *e, const unsigned int i, |
|
561 |
|
const struct zval *para) |
|
562 |
|
{ |
|
563 |
|
unsigned int s; |
|
564 |
|
struct zval *dst; |
|
565 |
|
|
|
566 |
|
s = (sizeof(struct zend_execute_data) + sizeof(struct zval) - 1) / sizeof(struct zval); |
|
567 |
|
dst = (struct zval *) e + s + i; |
|
568 |
|
memcpy(dst, para, sizeof(struct zval)); |
|
569 |
|
} |
|
570 |
|
|
|
571 |
584 |
static void php_pg_set_last_error(struct zend_execute_data *e, |
static void php_pg_set_last_error(struct zend_execute_data *e, |
572 |
585 |
struct zval *dbh, struct query *q) |
struct zval *dbh, struct query *q) |
573 |
586 |
{ |
{ |
|
... |
... |
static void php_pg_set_num_aff(struct zend_execute_data *e, struct zval *res, |
615 |
628 |
q->aff = rz.value.lval; |
q->aff = rz.value.lval; |
616 |
629 |
} |
} |
617 |
630 |
|
|
618 |
|
void *(*old_pg_query)(struct zend_execute_data *, struct zval *); |
|
|
631 |
|
static void *(*old_pg_query)(struct zend_execute_data *, struct zval *); |
619 |
632 |
static void *my_pg_query(struct zend_execute_data *e, struct zval *retv) |
static void *my_pg_query(struct zend_execute_data *e, struct zval *retv) |
620 |
633 |
{ |
{ |
621 |
634 |
void *ret; |
void *ret; |
|
... |
... |
static void *my_pg_query(struct zend_execute_data *e, struct zval *retv) |
678 |
691 |
return ret; |
return ret; |
679 |
692 |
} |
} |
680 |
693 |
|
|
681 |
|
void *(*old_pg_send_query)(struct zend_execute_data *, struct zval *); |
|
|
694 |
|
static void *(*old_pg_send_query)(struct zend_execute_data *, struct zval *); |
682 |
695 |
static void *my_pg_send_query(struct zend_execute_data *e, struct zval *retv) |
static void *my_pg_send_query(struct zend_execute_data *e, struct zval *retv) |
683 |
696 |
{ |
{ |
684 |
697 |
void *ret; |
void *ret; |
|
... |
... |
static void *my_pg_send_query(struct zend_execute_data *e, struct zval *retv) |
728 |
741 |
} |
} |
729 |
742 |
|
|
730 |
743 |
// TODO: not clear if on PHP 7 the parameter could be null |
// TODO: not clear if on PHP 7 the parameter could be null |
731 |
|
void *(*old_pg_get_result)(struct zend_execute_data *, struct zval *); |
|
|
744 |
|
static void *(*old_pg_get_result)(struct zend_execute_data *, struct zval *); |
732 |
745 |
static void *my_pg_get_result(struct zend_execute_data *e, struct zval *retv) |
static void *my_pg_get_result(struct zend_execute_data *e, struct zval *retv) |
733 |
746 |
{ |
{ |
734 |
747 |
void *ret; |
void *ret; |
|
... |
... |
static void *my_pg_get_result(struct zend_execute_data *e, struct zval *retv) |
780 |
793 |
return ret; |
return ret; |
781 |
794 |
} |
} |
782 |
795 |
|
|
783 |
|
void *(*old_pg_query_params)(struct zend_execute_data *, struct zval *); |
|
|
796 |
|
static void *(*old_pg_query_params)(struct zend_execute_data *, struct zval *); |
784 |
797 |
static void *my_pg_query_params(struct zend_execute_data *e, struct zval *retv) |
static void *my_pg_query_params(struct zend_execute_data *e, struct zval *retv) |
785 |
798 |
{ |
{ |
786 |
799 |
void *ret; |
void *ret; |
|
... |
... |
static void *my_pg_query_params(struct zend_execute_data *e, struct zval *retv) |
849 |
862 |
return ret; |
return ret; |
850 |
863 |
} |
} |
851 |
864 |
|
|
852 |
|
void *(*old_pg_send_query_params)(struct zend_execute_data *, struct zval *); |
|
|
865 |
|
static void *(*old_pg_send_query_params)(struct zend_execute_data *, struct zval *); |
853 |
866 |
static void *my_pg_send_query_params(struct zend_execute_data *e, struct zval *retv) |
static void *my_pg_send_query_params(struct zend_execute_data *e, struct zval *retv) |
854 |
867 |
{ |
{ |
855 |
868 |
void *ret; |
void *ret; |
|
... |
... |
static void *my_pg_send_query_params(struct zend_execute_data *e, struct zval *r |
903 |
916 |
} |
} |
904 |
917 |
|
|
905 |
918 |
|
|
|
919 |
|
|
|
920 |
|
static void *(*old_mysqli_error)(struct zend_execute_data *, struct zval *); |
|
921 |
|
static void *(*old_mysqli_affected_rows)(struct zend_execute_data *, struct zval *); |
|
922 |
|
static void *(*old_mysqli_num_rows)(struct zend_execute_data *, struct zval *); |
|
923 |
|
static void *(*old_mysqli_stmt_affected_rows)(struct zend_execute_data *, struct zval *); |
|
924 |
|
static void *(*old_mysqli_stmt_num_rows)(struct zend_execute_data *, struct zval *); |
|
925 |
|
|
|
926 |
|
static void php_mysqli_set_error(struct zend_execute_data *e, |
|
927 |
|
struct zval *link, struct query *q) |
|
928 |
|
{ |
|
929 |
|
struct zval rz; |
|
930 |
|
|
|
931 |
|
e->This.u2.num_args = 1; |
|
932 |
|
php_set_para(e, 0, link); |
|
933 |
|
|
|
934 |
|
// TODO: we need also the numeric representation of the error! |
|
935 |
|
xlog(50, " calling mysqli_error...\n"); |
|
936 |
|
old_mysqli_error(e, &rz); |
|
937 |
|
|
|
938 |
|
if (rz.u1.v.type == 6) { // string |
|
939 |
|
q->err = rz.value.str->val; |
|
940 |
|
q->err_len = rz.value.str->len; |
|
941 |
|
xlog(40, "%s: set error to [%s]\n", __func__, q->err); |
|
942 |
|
} else { |
|
943 |
|
q->err = "?"; |
|
944 |
|
q->err_len = 1; |
|
945 |
|
} |
|
946 |
|
} |
|
947 |
|
|
|
948 |
|
static void php_mysqli_set_num_aff(struct zend_execute_data *e, struct zval *res, |
|
949 |
|
struct query *q) |
|
950 |
|
{ |
|
951 |
|
struct zval rz; |
|
952 |
|
|
|
953 |
|
e->This.u2.num_args = 1; |
|
954 |
|
|
|
955 |
|
//xlog(1, " calling old pg_affected_rows...\n"); |
|
956 |
|
//php_zed_dump(" e: ", e); |
|
957 |
|
old_mysqli_affected_rows(e, &rz); // we need to pass a link here |
|
958 |
|
php_zval_dump(" aff_rows: ", &rz); |
|
959 |
|
q->aff = rz.value.lval; |
|
960 |
|
|
|
961 |
|
php_set_para(e, 0, res); |
|
962 |
|
//xlog(1, " calling old pg_num_rows...\n"); |
|
963 |
|
//php_zed_dump(" e: ", e); |
|
964 |
|
old_mysqli_num_rows(e, &rz); // we need a result here |
|
965 |
|
php_zval_dump(" num_rows: ", &rz); |
|
966 |
|
q->num = rz.value.lval; |
|
967 |
|
} |
|
968 |
|
|
|
969 |
|
static void php_mysqli_stmt_set_num_aff(struct zend_execute_data *e, |
|
970 |
|
struct nd_db_execute *q) |
|
971 |
|
{ |
|
972 |
|
struct zval rz; |
|
973 |
|
|
|
974 |
|
e->This.u2.num_args = 1; |
|
975 |
|
|
|
976 |
|
//xlog(1, " calling old mysqli_stmt_affected_rows...\n"); |
|
977 |
|
//php_zed_dump(" e: ", e); |
|
978 |
|
old_mysqli_stmt_affected_rows(e, &rz); |
|
979 |
|
php_zval_dump(" aff_rows: ", &rz); |
|
980 |
|
q->aff = rz.value.lval; |
|
981 |
|
|
|
982 |
|
//xlog(1, " calling old mysqli_stmt_num_rows...\n"); |
|
983 |
|
//php_zed_dump(" e: ", e); |
|
984 |
|
old_mysqli_stmt_num_rows(e, &rz); |
|
985 |
|
php_zval_dump(" num_rows: ", &rz); |
|
986 |
|
q->num = rz.value.lval; |
|
987 |
|
} |
|
988 |
|
|
906 |
989 |
void *(*old_mysqli_connect)(struct zend_execute_data *, struct zval *); |
void *(*old_mysqli_connect)(struct zend_execute_data *, struct zval *); |
907 |
990 |
static void *my_mysqli_connect(struct zend_execute_data *e, struct zval *retv) |
static void *my_mysqli_connect(struct zend_execute_data *e, struct zval *retv) |
908 |
991 |
{ |
{ |
|
... |
... |
static void *my_mysqli_query(struct zend_execute_data *e, struct zval *retv) |
1115 |
1198 |
memcpy(©_para, para, sizeof(struct zval)); |
memcpy(©_para, para, sizeof(struct zval)); |
1116 |
1199 |
|
|
1117 |
1200 |
if (retv->u1.v.type == 2) { // false |
if (retv->u1.v.type == 2) { // false |
1118 |
|
// TODO php_mysqli_set_last_error(e, dbh, &qs); // TODO is qs.res set here? |
|
|
1201 |
|
// TODO php_mysqli_set_error(e, dbh, &qs); // TODO is qs.res set here? |
1119 |
1202 |
// TODO: do we set num and aff? |
// TODO: do we set num and aff? |
1120 |
1203 |
qs.res = (void *) 0; |
qs.res = (void *) 0; |
1121 |
1204 |
} else if (retv->u1.v.type == 3) { // true (for queries not returning rows) |
} else if (retv->u1.v.type == 3) { // true (for queries not returning rows) |
|
... |
... |
static void *my_mysqli_query(struct zend_execute_data *e, struct zval *retv) |
1123 |
1206 |
qs.res = (void *) 1; |
qs.res = (void *) 1; |
1124 |
1207 |
} else if ((retv->u1.v.type == 8) || (retv->u1.v.type == 9)) { // object or resource |
} else if ((retv->u1.v.type == 8) || (retv->u1.v.type == 9)) { // object or resource |
1125 |
1208 |
qs.res = retv->value.p; |
qs.res = retv->value.p; |
1126 |
|
//TODO php_mysqli_set_num_aff(e, retv, &qs); |
|
|
1209 |
|
php_mysqli_set_num_aff(e, retv, &qs); |
1127 |
1210 |
do_restore = 1; |
do_restore = 1; |
1128 |
1211 |
} |
} |
1129 |
1212 |
|
|
|
... |
... |
static void *my_mysqli_close(struct zend_execute_data *e, struct zval *retv) |
1160 |
1243 |
|
|
1161 |
1244 |
if (retv->u1.v.type == 2) { // false |
if (retv->u1.v.type == 2) { // false |
1162 |
1245 |
c.ret = 0; |
c.ret = 0; |
1163 |
|
// TODO php_mysqli_set_last_error(e, dbh, &qs); // TODO is qs.res set here? |
|
|
1246 |
|
// TODO php_mysqli_set_error(e, dbh, &qs); // TODO is qs.res set here? |
1164 |
1247 |
// TODO: do we set num and aff? |
// TODO: do we set num and aff? |
1165 |
1248 |
} else if (retv->u1.v.type == 3) { // true (for queries not returning rows) |
} else if (retv->u1.v.type == 3) { // true (for queries not returning rows) |
1166 |
1249 |
c.ret = 1; |
c.ret = 1; |
|
... |
... |
static void *my_mysqli_fetch_all(struct zend_execute_data *e, struct zval *retv) |
1202 |
1285 |
return ret; |
return ret; |
1203 |
1286 |
php_zval_dump(" retv: ", retv); |
php_zval_dump(" retv: ", retv); |
1204 |
1287 |
|
|
|
1288 |
|
// TODO php_mysqli_set_error(e, dbh, &qs); // TODO is qs.res set here? |
1205 |
1289 |
if (retv->u1.v.type == 7) { // array |
if (retv->u1.v.type == 7) { // array |
1206 |
1290 |
struct zend_array *a = retv->value.arr; |
struct zend_array *a = retv->value.arr; |
1207 |
1291 |
q.num = a->nNumUsed; |
q.num = a->nNumUsed; |
1208 |
1292 |
//q.ret = 0; |
//q.ret = 0; |
1209 |
|
// TODO php_mysqli_set_last_error(e, dbh, &qs); // TODO is qs.res set here? |
|
1210 |
|
// TODO: do we set num and aff? |
|
|
1293 |
|
// TODO: do we set num and aff? Should we? We already count them in 'execute'. |
1211 |
1294 |
} else if (retv->u1.v.type == 3) { // true (for queries not returning rows) |
} else if (retv->u1.v.type == 3) { // true (for queries not returning rows) |
1212 |
1295 |
q.num = 0; |
q.num = 0; |
1213 |
1296 |
//q.ret = 1; |
//q.ret = 1; |
|
... |
... |
static void *my_mysqli_free_result(struct zend_execute_data *e, struct zval *ret |
1291 |
1374 |
void *(*old_mysqli_stmt_execute)(struct zend_execute_data *, struct zval *); |
void *(*old_mysqli_stmt_execute)(struct zend_execute_data *, struct zval *); |
1292 |
1375 |
static void *my_mysqli_stmt_execute(struct zend_execute_data *e, struct zval *retv) |
static void *my_mysqli_stmt_execute(struct zend_execute_data *e, struct zval *retv) |
1293 |
1376 |
{ |
{ |
1294 |
|
struct execute ex; |
|
|
1377 |
|
struct nd_db_execute ex; |
|
1378 |
|
char do_restore = 0; |
1295 |
1379 |
|
|
1296 |
1380 |
unsigned int num_args = e->This.u2.num_args; |
unsigned int num_args = e->This.u2.num_args; |
1297 |
1381 |
xlog(100, "%s: e=%p num_args=%hu\n", __func__, e, num_args); |
xlog(100, "%s: e=%p num_args=%hu\n", __func__, e, num_args); |
|
... |
... |
static void *my_mysqli_stmt_execute(struct zend_execute_data *e, struct zval *re |
1300 |
1384 |
ex.type = 'M'; |
ex.type = 'M'; |
1301 |
1385 |
ex.params.len = 0; |
ex.params.len = 0; |
1302 |
1386 |
|
|
1303 |
|
// res |
|
|
1387 |
|
struct zval *para = (struct zval *) e + s; |
|
1388 |
|
|
|
1389 |
|
// stmt |
1304 |
1390 |
struct zval *z = (struct zval *) e + s; s++; |
struct zval *z = (struct zval *) e + s; s++; |
1305 |
1391 |
php_zval_dump(" stmt: ", z); |
php_zval_dump(" stmt: ", z); |
1306 |
1392 |
ex.stmt = z->value.p; |
ex.stmt = z->value.p; |
|
... |
... |
static void *my_mysqli_stmt_execute(struct zend_execute_data *e, struct zval *re |
1311 |
1397 |
zend_array_to_params_array(&ex.params, za); |
zend_array_to_params_array(&ex.params, za); |
1312 |
1398 |
} |
} |
1313 |
1399 |
|
|
|
1400 |
|
unsigned int copy_num_args = num_args; |
|
1401 |
|
struct zval copy_para; |
|
1402 |
|
memcpy(©_para, para, sizeof(struct zval)); |
|
1403 |
|
|
1314 |
1404 |
ninedogs_process_db("mysqli_stmt_execute", NINEDOGS_DB_EXECUTE_START, &ex); |
ninedogs_process_db("mysqli_stmt_execute", NINEDOGS_DB_EXECUTE_START, &ex); |
1315 |
1405 |
void *ret = old_mysqli_stmt_execute(e, retv); |
void *ret = old_mysqli_stmt_execute(e, retv); |
1316 |
1406 |
if (!retv) |
if (!retv) |
|
... |
... |
static void *my_mysqli_stmt_execute(struct zend_execute_data *e, struct zval *re |
1318 |
1408 |
|
|
1319 |
1409 |
if (retv->u1.v.type == 3) { // true |
if (retv->u1.v.type == 3) { // true |
1320 |
1410 |
ex.ret = 1; |
ex.ret = 1; |
|
1411 |
|
php_mysqli_stmt_set_num_aff(e, &ex); |
|
1412 |
|
do_restore = 1; |
1321 |
1413 |
} else if (retv->u1.v.type == 2) { // false |
} else if (retv->u1.v.type == 2) { // false |
1322 |
1414 |
ex.ret = 0; |
ex.ret = 0; |
1323 |
1415 |
} |
} |
1324 |
1416 |
|
|
|
1417 |
|
e->This.u2.num_args = copy_num_args; |
|
1418 |
|
if (do_restore) |
|
1419 |
|
memcpy(para, ©_para, sizeof(struct zval)); |
|
1420 |
|
|
1325 |
1421 |
ninedogs_process_db("mysqli_stmt_execute", NINEDOGS_DB_EXECUTE_END, &ex); |
ninedogs_process_db("mysqli_stmt_execute", NINEDOGS_DB_EXECUTE_END, &ex); |
1326 |
1422 |
|
|
1327 |
1423 |
return ret; |
return ret; |
|
... |
... |
static void *my_mysqli_autocommit(struct zend_execute_data *e, struct zval *retv |
1443 |
1539 |
return ret; |
return ret; |
1444 |
1540 |
} |
} |
1445 |
1541 |
|
|
|
1542 |
|
void *(*old_mysqli_stmt_bind_param)(struct zend_execute_data *, struct zval *); |
|
1543 |
|
static void *my_mysqli_stmt_bind_param(struct zend_execute_data *e, struct zval *retv) |
|
1544 |
|
{ |
|
1545 |
|
struct nd_db_bind b; |
|
1546 |
|
|
|
1547 |
|
unsigned int num_args = e->This.u2.num_args; |
|
1548 |
|
xlog(100, "%s: e=%p num_args=%hu\n", __func__, e, num_args); |
|
1549 |
|
|
|
1550 |
|
unsigned int s = (sizeof(struct zend_execute_data) |
|
1551 |
|
+ sizeof(struct zval) - 1) / sizeof(struct zval); |
|
1552 |
|
b.type = 'M'; |
|
1553 |
|
|
|
1554 |
|
// stmt |
|
1555 |
|
struct zval *z = (struct zval *) e + s; s++; |
|
1556 |
|
//php_zval_dump(" stmt: ", z); |
|
1557 |
|
b.stmt = z->value.p; |
|
1558 |
|
|
|
1559 |
|
// types |
|
1560 |
|
z = (struct zval *) e + s; s++; |
|
1561 |
|
struct zend_string *xs = z->value.str; |
|
1562 |
|
b.types = xs->val; |
|
1563 |
|
b.types_len = xs->len; |
|
1564 |
|
|
|
1565 |
|
ninedogs_process_db("mysqli_stmt_bind_param", |
|
1566 |
|
NINEDOGS_DB_BIND_PARAM_START, &b); |
|
1567 |
|
void *ret = old_mysqli_stmt_bind_param(e, retv); |
|
1568 |
|
if (!retv) |
|
1569 |
|
return ret; |
|
1570 |
|
|
|
1571 |
|
if (retv->u1.v.type == 3) { // true |
|
1572 |
|
b.ret = 1; |
|
1573 |
|
} else if (retv->u1.v.type == 2) { // false |
|
1574 |
|
b.ret = 0; |
|
1575 |
|
} |
|
1576 |
|
|
|
1577 |
|
ninedogs_process_db("mysqli_stmt_bind_param", |
|
1578 |
|
NINEDOGS_DB_BIND_PARAM_END, &b); |
|
1579 |
|
|
|
1580 |
|
return ret; |
|
1581 |
|
} |
|
1582 |
|
|
|
1583 |
|
|
1446 |
1584 |
|
|
1447 |
1585 |
|
|
1448 |
1586 |
struct zend_module_entry *(*old_get_module)(void); |
struct zend_module_entry *(*old_get_module)(void); |
|
... |
... |
static struct zend_module_entry *php_hook_get_module_func(void) |
1545 |
1683 |
} else if (strcmp(fe->fname, "mysqli_close") == 0) { |
} else if (strcmp(fe->fname, "mysqli_close") == 0) { |
1546 |
1684 |
old_mysqli_close = fe->handler; |
old_mysqli_close = fe->handler; |
1547 |
1685 |
fe->handler = my_mysqli_close; |
fe->handler = my_mysqli_close; |
|
1686 |
|
} else if (strcmp(fe->fname, "mysqli_affected_rows") == 0) { |
|
1687 |
|
old_mysqli_stmt_affected_rows = fe->handler; |
1548 |
1688 |
} else if (strcmp(fe->fname, "mysqli_connect") == 0) { |
} else if (strcmp(fe->fname, "mysqli_connect") == 0) { |
1549 |
1689 |
old_mysqli_connect = fe->handler; |
old_mysqli_connect = fe->handler; |
1550 |
1690 |
fe->handler = my_mysqli_connect; |
fe->handler = my_mysqli_connect; |
|
1691 |
|
} else if (strcmp(fe->fname, "mysqli_error") == 0) { |
|
1692 |
|
old_mysqli_error = fe->handler; |
1551 |
1693 |
} else if (strcmp(fe->fname, "mysqli_fetch_all") == 0) { |
} else if (strcmp(fe->fname, "mysqli_fetch_all") == 0) { |
1552 |
1694 |
old_mysqli_fetch_all = fe->handler; |
old_mysqli_fetch_all = fe->handler; |
1553 |
1695 |
fe->handler = my_mysqli_fetch_all; |
fe->handler = my_mysqli_fetch_all; |
|
... |
... |
static struct zend_module_entry *php_hook_get_module_func(void) |
1563 |
1705 |
} else if (strcmp(fe->fname, "mysqli_prepare") == 0) { |
} else if (strcmp(fe->fname, "mysqli_prepare") == 0) { |
1564 |
1706 |
old_mysqli_prepare = fe->handler; |
old_mysqli_prepare = fe->handler; |
1565 |
1707 |
fe->handler = my_mysqli_prepare; |
fe->handler = my_mysqli_prepare; |
|
1708 |
|
} else if (strcmp(fe->fname, "mysqli_num_rows") == 0) { |
|
1709 |
|
old_mysqli_num_rows = fe->handler; |
1566 |
1710 |
} else if (strcmp(fe->fname, "mysqli_real_connect") == 0) { |
} else if (strcmp(fe->fname, "mysqli_real_connect") == 0) { |
1567 |
1711 |
old_mysqli_real_connect = fe->handler; |
old_mysqli_real_connect = fe->handler; |
1568 |
1712 |
fe->handler = my_mysqli_real_connect; |
fe->handler = my_mysqli_real_connect; |
|
1713 |
|
} else if (strcmp(fe->fname, "mysqli_stmt_affected_rows") == 0) { |
|
1714 |
|
old_mysqli_stmt_affected_rows = fe->handler; |
1569 |
1715 |
} else if (strcmp(fe->fname, "mysqli_stmt_execute") == 0) { |
} else if (strcmp(fe->fname, "mysqli_stmt_execute") == 0) { |
1570 |
1716 |
old_mysqli_stmt_execute = fe->handler; |
old_mysqli_stmt_execute = fe->handler; |
1571 |
1717 |
fe->handler = my_mysqli_stmt_execute; |
fe->handler = my_mysqli_stmt_execute; |
|
1718 |
|
} else if (strcmp(fe->fname, "mysqli_stmt_bind_param") == 0) { |
|
1719 |
|
old_mysqli_stmt_bind_param = fe->handler; |
|
1720 |
|
fe->handler = my_mysqli_stmt_bind_param; |
|
1721 |
|
} else if (strcmp(fe->fname, "mysqli_stmt_num_rows") == 0) { |
|
1722 |
|
old_mysqli_stmt_num_rows = fe->handler; |
1572 |
1723 |
} else if (strcmp(fe->fname, "mysqli_stmt_prepare") == 0) { |
} else if (strcmp(fe->fname, "mysqli_stmt_prepare") == 0) { |
1573 |
1724 |
old_mysqli_stmt_prepare = fe->handler; |
old_mysqli_stmt_prepare = fe->handler; |
1574 |
1725 |
fe->handler = my_mysqli_stmt_prepare; |
fe->handler = my_mysqli_stmt_prepare; |
File docs/pre1.tex changed (mode: 100644) (index 8207e00..19fc9fe) |
9 |
9 |
|
|
10 |
10 |
\title{ninedogs project introduction} |
\title{ninedogs project introduction} |
11 |
11 |
\subtitle{ninedogs workshop for Devs and DevOps (tracing)} |
\subtitle{ninedogs workshop for Devs and DevOps (tracing)} |
12 |
|
\author{Catalin(ux) M. BOIE} |
|
|
12 |
|
\author{Catalin(ux) M. BOIE - ninedogs@embedromix.ro} |
13 |
13 |
\date{2022-11-09} |
\date{2022-11-09} |
14 |
14 |
%\titlegraphic{\includegraphics[width=2.5cm]{ninedogs.svg}} |
%\titlegraphic{\includegraphics[width=2.5cm]{ninedogs.svg}} |
15 |
15 |
|
|
|
34 |
34 |
\item A set of tools helping the Developers, database/system admins and DevOps |
\item A set of tools helping the Developers, database/system admins and DevOps |
35 |
35 |
to get more information from the running processes. |
to get more information from the running processes. |
36 |
36 |
\item A client/server application streaming tracing information to the server |
\item A client/server application streaming tracing information to the server |
37 |
|
for later analysis. |
|
|
37 |
|
for later analysis (future). |
38 |
38 |
\item A log collection tool (future). |
\item A log collection tool (future). |
39 |
39 |
\item An alerting tool for certificate imminent expiration and security issues alerting. |
\item An alerting tool for certificate imminent expiration and security issues alerting. |
40 |
|
\item A tool for live patching of applications (Log4J etc.). |
|
|
40 |
|
\item A tool for live patching of applications (log4j etc.) (future). |
|
41 |
|
\item License is AGPL, the most developer and user friendly possible. |
41 |
42 |
\end{itemize} |
\end{itemize} |
42 |
43 |
\end{block} |
\end{block} |
43 |
44 |
\end{frame} |
\end{frame} |
|
46 |
47 |
\begin{block}{How ninedogs is working?} |
\begin{block}{How ninedogs is working?} |
47 |
48 |
\begin{itemize} |
\begin{itemize} |
48 |
49 |
\item It uses LD\_PRELOAD mechanism to hook all interesting shared libraries calls. |
\item It uses LD\_PRELOAD mechanism to hook all interesting shared libraries calls. |
49 |
|
\item Examples of hooked funtions (not syscalls! it does not use ptrace): recv, send, open, |
|
|
50 |
|
\item Examples of hooked functions (not syscalls! it does not use ptrace): recv, send, open, |
50 |
51 |
mysqli\_fetch\_array, pg\_pconnect, sqlite3\_open\_v2, syslog etc. |
mysqli\_fetch\_array, pg\_pconnect, sqlite3\_open\_v2, syslog etc. |
51 |
52 |
\item Many more will come in each release. |
\item Many more will come in each release. |
52 |
53 |
\end{itemize} |
\end{itemize} |
|
65 |
66 |
\end{block} |
\end{block} |
66 |
67 |
\end{frame} |
\end{frame} |
67 |
68 |
|
|
68 |
|
|
|
69 |
|
\subsection{Preparations for using ninedogs tracing} |
|
70 |
|
|
|
71 |
69 |
\begin{frame} |
\begin{frame} |
72 |
|
\begin{block}{Installation} |
|
|
70 |
|
\begin{block}{What is the performance impact of ninedogs tracing} |
73 |
71 |
\begin{itemize} |
\begin{itemize} |
74 |
|
\item With the help of https://rocketgit.com, we build ninedogs for a lot of |
|
75 |
|
distributions and architectures. |
|
76 |
|
Check \href{https://rocketgit.com/op/pkg_repos}{https://rocketgit.com/op/pkg\_repos} |
|
77 |
|
to see if your distro/arch is supported. Ask if not there. |
|
78 |
|
\item ninedogs can be installed both in a normal Linux distribution or in a container. |
|
|
72 |
|
\item It uses shared memory as a ring buffer to pass information to the tracer. |
|
73 |
|
\item The biggest cost is copying from memory to memory (negligible). |
|
74 |
|
\item It does not block if the ring is full. |
|
75 |
|
\item It uses a small amount of memory compared with other products. |
79 |
76 |
\end{itemize} |
\end{itemize} |
80 |
77 |
\end{block} |
\end{block} |
81 |
78 |
\end{frame} |
\end{frame} |
82 |
79 |
|
|
83 |
80 |
|
|
|
81 |
|
\section{Installation and basic usage} |
|
82 |
|
|
|
83 |
|
\subsection{Preparations for using ninedogs tracing} |
|
84 |
|
|
|
85 |
|
\begin{frame}{Installation - general info} |
|
86 |
|
\begin{itemize} |
|
87 |
|
\item With the help of \href{https://rocketgit.com}{RocketGit project}, |
|
88 |
|
we build ninedogs for multiple distributions and architectures. |
|
89 |
|
|
|
90 |
|
Check \href{https://rocketgit.com/op/pkg_repos}{https://rocketgit.com/op/pkg\_repos} |
|
91 |
|
to see if your distro/arch is supported. Ask if is not there. |
|
92 |
|
\item ninedogs can be installed both in a normal Linux distribution or in a container. |
|
93 |
|
\end{itemize} |
|
94 |
|
\end{frame} |
|
95 |
|
|
|
96 |
|
\begin{frame}[fragile]{VMs/baremetal installation and usage} |
|
97 |
|
\begin{block}{Fedora/RedHat/Alma/Rocky} |
|
98 |
|
\tiny |
|
99 |
|
\begin{verbatim} |
|
100 |
|
# Installing RocketGit repository (so you will get updates automatically) |
|
101 |
|
dnf install https://rocketgit.com/op/pkgrepo/main/global/testing/fedora/37/x86_64/os/rocketgit-global-testing-1.1-1.noarch.rpm |
|
102 |
|
# Installing package |
|
103 |
|
dnf install catalinux+ninedogs |
|
104 |
|
\end{verbatim} |
|
105 |
|
\end{block} |
|
106 |
|
\begin{block}{Usage in a systemd service file} |
|
107 |
|
\small |
|
108 |
|
\begin{verbatim} |
|
109 |
|
TODO |
|
110 |
|
\end{verbatim} |
|
111 |
|
\end{block} |
|
112 |
|
\end{frame} |
|
113 |
|
|
|
114 |
|
\begin{frame}[fragile]{Container installation and usage} |
|
115 |
|
\begin{block}{Dockerfile} |
|
116 |
|
\tiny |
|
117 |
|
\begin{verbatim} |
|
118 |
|
FROM fedora:37 |
|
119 |
|
[...] |
|
120 |
|
RUN dnf -y --setopt=tsflags=nodocs install \ |
|
121 |
|
https://rocketgit.com/op/pkgrepo/main/global/testing/fedora/37/x86_64/os/rocketgit-global-testing-1.1-1.noarch.rpm \ |
|
122 |
|
&& dnf -y --setopt=tsflags=nodocs install catalinux+ninedogs \ |
|
123 |
|
&& dnf -y clean all |
|
124 |
|
\end{verbatim} |
|
125 |
|
\end{block} |
|
126 |
|
\begin{block}{In the start script...} |
|
127 |
|
\small |
|
128 |
|
\begin{verbatim} |
|
129 |
|
LD_PRELOAD=ninedogs.so path_to_your_program |
|
130 |
|
\end{verbatim} |
|
131 |
|
\end{block} |
|
132 |
|
\begin{block}{... or set at run-time} |
|
133 |
|
\small |
|
134 |
|
\begin{verbatim} |
|
135 |
|
podman run -e LD_PRELOAD=ninedogs.so image command |
|
136 |
|
docker run -e LD_PRELOAD=ninedogs.so image command |
|
137 |
|
\end{verbatim} |
|
138 |
|
\end{block} |
|
139 |
|
\end{frame} |
|
140 |
|
|
|
141 |
|
|
|
142 |
|
|
84 |
143 |
\section{Demo} |
\section{Demo} |
85 |
144 |
|
|
86 |
145 |
\subsection{Real life examples} |
\subsection{Real life examples} |
87 |
146 |
|
|
88 |
|
|
|
89 |
147 |
\begin{frame}[fragile]{MySQL connection} |
\begin{frame}[fragile]{MySQL connection} |
|
148 |
|
\begin{block}{PHP code} |
|
149 |
|
\tiny |
|
150 |
|
\begin{verbatim} |
|
151 |
|
$db = mysqli_init(); |
|
152 |
|
mysqli_real_connect($db, 'h1', 'ninedogs', 'pass', 'ninedogs', 3306, FALSE, MYSQLI_CLIENT_COMPRESS); |
|
153 |
|
\end{verbatim} |
|
154 |
|
\end{block} |
90 |
155 |
\begin{block}{strace} |
\begin{block}{strace} |
91 |
156 |
\tiny |
\tiny |
92 |
157 |
\begin{verbatim} |
\begin{verbatim} |
|
... |
... |
fcntl(5, F_GETFL) = 0x2 (flags O_RDWR) |
95 |
160 |
fcntl(5, F_SETFL, O_RDWR|O_NONBLOCK) = 0 |
fcntl(5, F_SETFL, O_RDWR|O_NONBLOCK) = 0 |
96 |
161 |
connect(5, {sa_family=AF_INET, sin_port=htons(3306), sin_addr=inet_addr("x.x.x.x")},16) |
connect(5, {sa_family=AF_INET, sin_port=htons(3306), sin_addr=inet_addr("x.x.x.x")},16) |
97 |
162 |
= -1 EINPROGRESS (Operation now in progress) |
= -1 EINPROGRESS (Operation now in progress) |
98 |
|
poll([{fd=5, events=POLLIN\|POLLOUT\|POLLERR\|POLLHUP}], 1, 60000) = 1 ([{fd=5, revents=POLLOUT}]) |
|
|
163 |
|
poll([{fd=5, events=POLLIN|POLLOUT|POLLERR|POLLHUP}], 1, 60000) = 1 ([{fd=5, revents=POLLOUT}]) |
99 |
164 |
getsockopt(5, SOL_SOCKET, SO_ERROR, [0], [4]) = 0 |
getsockopt(5, SOL_SOCKET, SO_ERROR, [0], [4]) = 0 |
100 |
|
fcntl\(5, F_SETFL, O_RDWR\) = 0 |
|
|
165 |
|
fcntl(5, F_SETFL, O_RDWR) = 0 |
101 |
166 |
setsockopt(5, SOL_TCP, TCP_NODELAY, [1], 4) = 0 |
setsockopt(5, SOL_TCP, TCP_NODELAY, [1], 4) = 0 |
102 |
167 |
setsockopt(5, SOL_SOCKET, SO_KEEPALIVE, [1], 4) = 0 |
setsockopt(5, SOL_SOCKET, SO_KEEPALIVE, [1], 4) = 0 |
103 |
168 |
poll([{fd=5, events=POLLIN|POLLERR|POLLHUP}], 1, 86400000) = 1 ([{fd=5, revents=POLLIN}]) |
poll([{fd=5, events=POLLIN|POLLERR|POLLHUP}], 1, 86400000) = 1 ([{fd=5, revents=POLLIN}]) |
104 |
169 |
recvfrom(5, "Y\0\0\0\n5.5.5-10.5.16-MariaDB...", 32768, MSG_DONTWAIT, NULL, NULL) = 93 |
recvfrom(5, "Y\0\0\0\n5.5.5-10.5.16-MariaDB...", 32768, MSG_DONTWAIT, NULL, NULL) = 93 |
105 |
170 |
sendto(5, "\203\0\0\1\315...", 135, MSG_DONTWAIT, NULL, 0) = 135 |
sendto(5, "\203\0\0\1\315...", 135, MSG_DONTWAIT, NULL, 0) = 135 |
106 |
171 |
poll([{fd=5, events=POLLIN|POLLERR|POLLHUP}], 1, 86400000) = 1 ([{fd=5, revents=POLLIN}]) |
poll([{fd=5, events=POLLIN|POLLERR|POLLHUP}], 1, 86400000) = 1 ([{fd=5, revents=POLLIN}]) |
107 |
|
recvfrom(5, "\7\0\0\2\0\0\0\2\0\0\0", 32768, MSG_DONTWAIT, NULL, NULL) = 11} |
|
|
172 |
|
recvfrom(5, "\7\0\0\2\0\0\0\2\0\0\0", 32768, MSG_DONTWAIT, NULL, NULL) = 11 |
|
173 |
|
\end{verbatim} |
|
174 |
|
\end{block} |
|
175 |
|
\begin{block}{nd-trace} |
|
176 |
|
\tiny |
|
177 |
|
\begin{verbatim} |
|
178 |
|
mysqli_real_connect(link=0x7ffba947f190, 'host=h1 user=ninedogs port=3306 db=ninedogs socket=', |
|
179 |
|
flags='0x20|COMPRESS') |
|
180 |
|
[strace like output (connect/poll/recvfrom/sendto etc.) omitted] |
|
181 |
|
mysqli_real_connect(link=0x7ffba947f190, 'host=h1 user=ninedogs port=3306 db=ninedogs socket=', |
|
182 |
|
flags='0x20|COMPRESS') = ok |
108 |
183 |
\end{verbatim} |
\end{verbatim} |
109 |
184 |
\end{block} |
\end{block} |
|
185 |
|
\end{frame} |
|
186 |
|
|
110 |
187 |
|
|
|
188 |
|
\begin{frame}[fragile]{PostgreSQL query} |
|
189 |
|
\begin{block}{PHP code} |
|
190 |
|
\tiny |
|
191 |
|
\begin{verbatim} |
|
192 |
|
$sql = 'SELECT id FROM n1 WHERE id = $1 OR id = $2 OR d = $3 OR a1 = $4 OR a1 = $5'; |
|
193 |
|
$params = array(3, '4', 1.2, NULL, FALSE); |
|
194 |
|
$res = pg_query_params($db, $sql, $params); |
|
195 |
|
\end{verbatim} |
|
196 |
|
\end{block} |
|
197 |
|
\begin{block}{strace} |
|
198 |
|
\tiny |
|
199 |
|
\begin{verbatim} |
|
200 |
|
sendto(10, "P\0\0\0R\0SELECT id FROM n1 WHERE id = $1 OR id = $2 OR d = $3 OR a1 = $4 OR a1 = $5 |
|
201 |
|
\0\0\0B\0\0\0'\0\0\0\0\0\5\0\0\0\0013\0\0\0\0014\0\0\0\0031.2\377\377\377\377\0\0\0\0\0 |
|
202 |
|
\1\0\0D\0\0\0\6P\0E\0\0\0\t\0\0\0\0\0S\0\0\0\4", 145, MSG_NOSIGNAL, NULL, 0) = 145 |
|
203 |
|
\end{verbatim} |
|
204 |
|
\end{block} |
|
205 |
|
\begin{block}{nd-trace} |
|
206 |
|
\tiny |
|
207 |
|
\begin{verbatim} |
|
208 |
|
pg_query_params(h=0x7fb55be6a4d0, 'SELECT id FROM n1 WHERE id = $1 OR id = $2 OR d = $3 OR a1 = $4 OR a1 = $5') |
|
209 |
|
{1:long:3, 2:str:'4', 3:double:1.200000, 4:NULL, 5:str:'false'} |
|
210 |
|
pg_query_params(h=0x7fb55be6a4d0, 'SELECT id FROM n1 WHERE id = $1 OR id = $2 OR d = $3 OR a1 = $4 OR a1 = $5') |
|
211 |
|
= 0x7fb55be03198 [2 rows, 2 aff] |
|
212 |
|
\end{verbatim} |
|
213 |
|
\end{block} |
|
214 |
|
\end{frame} |
|
215 |
|
|
|
216 |
|
|
|
217 |
|
\begin{frame}[fragile]{MySQL query} |
|
218 |
|
\begin{block}{PHP code} |
|
219 |
|
\tiny |
|
220 |
|
\begin{verbatim} |
|
221 |
|
$stmt = mysqli_stmt_init($db); |
|
222 |
|
$sql = 'SELECT id, a1 FROM n1 WHERE id = ? OR id = ? OR d = ? OR a1 = ? OR a1 = ?'; |
|
223 |
|
mysqli_stmt_prepare($stmt, $sql); |
|
224 |
|
mysqli_stmt_execute($stmt, array('1', '2', '3', '4', 5)); |
|
225 |
|
\end{verbatim} |
|
226 |
|
\end{block} |
|
227 |
|
\begin{block}{strace} |
|
228 |
|
\tiny |
|
229 |
|
\begin{verbatim} |
|
230 |
|
sendto(5, "J\0\0\0\26SELECT id, a1 FROM n1 WHERE id = ? OR id = ? OR d = ? OR a1 = ? OR a1 = ?", |
|
231 |
|
78, MSG_DONTWAIT, NULL, 0) = 78 |
|
232 |
|
sendto(5, " \0\0\0\27\4\0\0\0\0\1\0\0\0\0\1\375\0\375\0\375\0\375\0\375\0\0011\0012\0013\0014\0015", |
|
233 |
|
36, MSG_DONTWAIT, NULL, 0) = 36 |
|
234 |
|
\end{verbatim} |
|
235 |
|
\end{block} |
111 |
236 |
\begin{block}{nd-trace} |
\begin{block}{nd-trace} |
112 |
237 |
\tiny |
\tiny |
113 |
238 |
\begin{verbatim} |
\begin{verbatim} |
114 |
|
mysqli_real_connect(link=0x7fc52127f010, 'host=h1 user=ninedogs port=3306 db=ninedogs socket=', |
|
115 |
|
flags='0x40|SSL_DONT_VERIFY_SERVER_CERT') |
|
116 |
|
[strace like output (connect/poll/recvfrom/sendto etc.) ommited] |
|
117 |
|
mysqli_real_connect(link=0x7fc52127f010, 'host=h1 user=ninedogs port=3306 db=ninedogs socket=', |
|
118 |
|
flags='0x40|SSL_DONT_VERIFY_SERVER_CERT') = ok |
|
|
239 |
|
mysqli_stmt_prepare(stmt=0x7fc52127c390, 'SELECT id, a1 FROM n1 WHERE id = ? OR id = ? OR d = ? OR a1 = ? OR a1 = ?') |
|
240 |
|
mysqli_stmt_prepare(stmt=0x7fc52127c390, 'SELECT id, a1 FROM n1 WHERE id = ? OR id = ? OR d = ? OR a1 = ? OR a1 = ?') = ok |
|
241 |
|
mysqli_stmt_execute(stmt=0x7fc52127c390, {1:str:'1', 2:str:'2', 3:str:'3', 4:str:'4', 5:long:5}) |
|
242 |
|
mysqli_stmt_execute(stmt=0x7fc52127c390) = ok |
119 |
243 |
\end{verbatim} |
\end{verbatim} |
120 |
244 |
\end{block} |
\end{block} |
121 |
245 |
\end{frame} |
\end{frame} |
122 |
246 |
|
|
123 |
247 |
|
|
124 |
248 |
\begin{frame}[fragile]{sqlite3} |
\begin{frame}[fragile]{sqlite3} |
|
249 |
|
\begin{block}{Python code} |
|
250 |
|
\tiny |
|
251 |
|
\begin{verbatim} |
|
252 |
|
db = sqlite3.connect('/bla/sqlite1.db') |
|
253 |
|
cursor = db.cursor() |
|
254 |
|
query = 'INSERT INTO test1 VALUES (:id, :val);' |
|
255 |
|
cursor.execute(query, { "id": 1, "val": "first_value"}) |
|
256 |
|
\end{verbatim} |
|
257 |
|
\end{block} |
125 |
258 |
\begin{block}{strace} |
\begin{block}{strace} |
126 |
259 |
\tiny |
\tiny |
127 |
260 |
\begin{verbatim} |
\begin{verbatim} |
128 |
|
openat(AT_FDCWD, "/date/sync/no-crypt/sync1/Dev/ninedogs/test/python/sqlite1.db", |
|
129 |
|
O_RDWR|O_CREAT|O_NOFOLLOW|O_CLOEXEC, 0644) = 3 |
|
|
261 |
|
openat(AT_FDCWD, "/bla/sqlite1.db", O_RDWR|O_CREAT|O_NOFOLLOW|O_CLOEXEC, 0644) = 3 |
130 |
262 |
pread64(3, "SQLite format 3...", 100, 0) = 100 |
pread64(3, "SQLite format 3...", 100, 0) = 100 |
131 |
263 |
fcntl(3, F_SETLK, {l_type=F_RDLCK, l_whence=SEEK_SET, l_start=1073741824, l_len=1}) = 0 |
fcntl(3, F_SETLK, {l_type=F_RDLCK, l_whence=SEEK_SET, l_start=1073741824, l_len=1}) = 0 |
132 |
264 |
[lots of pread64/pwrite64/fcntl removed] |
[lots of pread64/pwrite64/fcntl removed] |
133 |
265 |
pwrite64(3, "...\0\16\1\3\t#first_value", 4096, 4096) = 4096 |
pwrite64(3, "...\0\16\1\3\t#first_value", 4096, 4096) = 4096 |
134 |
266 |
\end{verbatim} |
\end{verbatim} |
135 |
267 |
\end{block} |
\end{block} |
136 |
|
|
|
137 |
268 |
\begin{block}{nd-trace} |
\begin{block}{nd-trace} |
138 |
269 |
\tiny |
\tiny |
139 |
270 |
\begin{verbatim} |
\begin{verbatim} |
140 |
|
sqlite3_open_v2('sqlite1.db', 0x6|READWRITE|CREATE, '') |
|
141 |
|
sqlite3_open_v2('sqlite1.db', 0x55c13dfba5a8, 0x6|READWRITE|CREATE, '') = OK |
|
|
271 |
|
sqlite3_open_v2('/bla/sqlite1.db', 0x6|READWRITE|CREATE, '') |
|
272 |
|
sqlite3_open_v2('/bla/sqlite1.db', 0x55c13dfba5a8, 0x6|READWRITE|CREATE, '') = ok |
142 |
273 |
sqlite3_prepare_v2(0x55794910b5a8, 'INSERT INTO test1 VALUES (:id, :val);', -1, stmt, tail) |
sqlite3_prepare_v2(0x55794910b5a8, 'INSERT INTO test1 VALUES (:id, :val);', -1, stmt, tail) |
143 |
|
sqlite3_prepare_v2(0x55794910b5a8, 'INSERT INTO test1 VALUES (:id, :val);', -1, 0x55794918e388, tail) = OK |
|
144 |
|
sqlite3_bind_int64(stmt=0x5594c1d78388, index=1, value=1) = OK |
|
145 |
|
sqlite3_bind_text(stmt=0x55d53848e388, index=2, 'first_value') = OK |
|
|
274 |
|
sqlite3_prepare_v2(0x55794910b5a8, 'INSERT INTO test1 VALUES (:id, :val);', -1, 0x55794918e388, tail) = ok |
|
275 |
|
sqlite3_bind_int64(stmt=0x5594c1d78388, index=1, value=1) = ok |
|
276 |
|
sqlite3_bind_text(stmt=0x55d53848e388, index=2, 'first_value') = ok |
146 |
277 |
sqlite3_step(0x5594c1d78388) |
sqlite3_step(0x5594c1d78388) |
147 |
|
sqlite3_step(0x5594c1d78388) = DONE |
|
148 |
|
sqlite3_finalize(0x5594c1d78388) = OK |
|
|
278 |
|
sqlite3_step(0x5594c1d78388) = DONE |
|
279 |
|
sqlite3_finalize(0x5594c1d78388) = ok |
149 |
280 |
\end{verbatim} |
\end{verbatim} |
150 |
281 |
\end{block} |
\end{block} |
151 |
282 |
\end{frame} |
\end{frame} |
152 |
283 |
|
|
153 |
|
|
|
154 |
284 |
\begin{frame}[fragile]{Hostname resolving} |
\begin{frame}[fragile]{Hostname resolving} |
155 |
285 |
\begin{block}{strace} |
\begin{block}{strace} |
156 |
286 |
\tiny |
\tiny |
|
... |
... |
epoll_ctl(13, EPOLL_CTL_DEL, 20, 0x7f43aa4aaa04) = 0 |
175 |
305 |
close(20) |
close(20) |
176 |
306 |
\end{verbatim} |
\end{verbatim} |
177 |
307 |
\end{block} |
\end{block} |
178 |
|
|
|
179 |
308 |
\begin{block}{nd-trace} |
\begin{block}{nd-trace} |
180 |
309 |
\tiny |
\tiny |
181 |
310 |
\begin{verbatim} |
\begin{verbatim} |
|
... |
... |
gethostbyname_r('bla.com.com.com') |
186 |
315 |
\end{frame} |
\end{frame} |
187 |
316 |
|
|
188 |
317 |
|
|
189 |
|
\section{Other interesting things} |
|
|
318 |
|
\subsection{Other interesting things} |
190 |
319 |
|
|
191 |
320 |
\begin{frame}[fragile]{Segmentation fault} |
\begin{frame}[fragile]{Segmentation fault} |
192 |
321 |
\begin{block}{strace} |
\begin{block}{strace} |
|
... |
... |
gethostbyname_r('bla.com.com.com') |
197 |
326 |
Segmentation fault (core dumped) |
Segmentation fault (core dumped) |
198 |
327 |
\end{verbatim} |
\end{verbatim} |
199 |
328 |
\end{block} |
\end{block} |
200 |
|
|
|
201 |
329 |
\begin{block}{nd-trace} |
\begin{block}{nd-trace} |
202 |
330 |
\tiny |
\tiny |
203 |
331 |
\begin{verbatim} |
\begin{verbatim} |
|
... |
... |
Segmentation fault (core dumped) |
212 |
340 |
\end{frame} |
\end{frame} |
213 |
341 |
|
|
214 |
342 |
|
|
215 |
|
\begin{frame}[fragile]{bla - no tiny} |
|
216 |
|
\begin{block}{} |
|
217 |
|
\tiny |
|
218 |
|
\begin{verbatim} |
|
219 |
|
\end{verbatim} |
|
220 |
|
\end{block} |
|
|
343 |
|
\section{Misc} |
221 |
344 |
|
|
222 |
|
\begin{block}{ - nd-trace} |
|
223 |
|
\tiny |
|
224 |
|
\begin{verbatim} |
|
225 |
|
text |
|
226 |
|
\end{verbatim} |
|
227 |
|
\end{block} |
|
|
345 |
|
\subsection{What is coming next?} |
|
346 |
|
|
|
347 |
|
\begin{frame}{What is coming next?} |
|
348 |
|
\begin{itemize} |
|
349 |
|
\item More functions interception. |
|
350 |
|
\item Send logs to the server (intercept any open of filenames containing '.log' or '/logs?/'). |
|
351 |
|
\item Adding a cron to report used certificates close to expiration date. |
|
352 |
|
\item nd-trace: report statistics (number of calls and average time spent per function). |
|
353 |
|
\end{itemize} |
|
354 |
|
\end{frame} |
|
355 |
|
|
|
356 |
|
\begin{frame} |
|
357 |
|
\center |
|
358 |
|
Thank you! |
|
359 |
|
|
|
360 |
|
Contact: ninedogs@embedromix.ro |
|
361 |
|
|
|
362 |
|
Download/history/artifacts: \href{https://rocketgit.com/user/catalinux/ninedogs}{https://rocketgit.com/user/catalinux/ninedogs} |
|
363 |
|
|
|
364 |
|
We need sponsors, please contact us if you want to become one. |
228 |
365 |
\end{frame} |
\end{frame} |
229 |
366 |
|
|
230 |
367 |
|
|
File trace/nd-trace.c changed (mode: 100644) (index d07ee21..6843c12) |
... |
... |
static int decode_sqlite3_ret(char *out, unsigned out_size, |
608 |
608 |
unsigned int ret = decode32(d, i); |
unsigned int ret = decode32(d, i); |
609 |
609 |
|
|
610 |
610 |
switch (ret) { |
switch (ret) { |
611 |
|
case 0: snprintf(out, out_size, "OK"); break; |
|
|
611 |
|
case 0: snprintf(out, out_size, "ok"); break; |
612 |
612 |
case 1: snprintf(out, out_size, "ERROR"); break; |
case 1: snprintf(out, out_size, "ERROR"); break; |
613 |
613 |
case 2: snprintf(out, out_size, "INTERNAL"); break; |
case 2: snprintf(out, out_size, "INTERNAL"); break; |
614 |
614 |
case 3: snprintf(out, out_size, "PERM"); break; |
case 3: snprintf(out, out_size, "PERM"); break; |
|
... |
... |
static void decode_query_params(char *out, size_t out_size, |
747 |
747 |
rest -= 2; |
rest -= 2; |
748 |
748 |
} |
} |
749 |
749 |
|
|
750 |
|
char *add = ""; |
|
|
750 |
|
char *add = "", do_break = 0; |
751 |
751 |
for (unsigned short j = 0; j < params_len; j++) { |
for (unsigned short j = 0; j < params_len; j++) { |
752 |
752 |
char value[64]; |
char value[64]; |
753 |
753 |
uint8_t type = decode8(d, i); |
uint8_t type = decode8(d, i); |
754 |
|
if (type == 1) { // long |
|
|
754 |
|
if (type == 0) { // NULL |
|
755 |
|
snprintf(value, sizeof(value), |
|
756 |
|
"%hu:NULL", j + 1); |
|
757 |
|
} else if (type == 1) { // long |
755 |
758 |
snprintf(value, sizeof(value), |
snprintf(value, sizeof(value), |
756 |
759 |
"%hu:long:%ld", j + 1, decode64(d, i)); |
"%hu:long:%ld", j + 1, decode64(d, i)); |
757 |
760 |
} else if (type == 2) { // double |
} else if (type == 2) { // double |
|
761 |
|
double dd; |
|
762 |
|
uint64_t u = decode64(d, i); |
|
763 |
|
memcpy(&dd, &u, 8); |
758 |
764 |
snprintf(value, sizeof(value), |
snprintf(value, sizeof(value), |
759 |
|
"%hu:double:%f", j + 1, (double) decode64(d, i)); |
|
|
765 |
|
"%hu:double:%f", j + 1, dd); |
760 |
766 |
} else if (type == 3) { // string |
} else if (type == 3) { // string |
761 |
767 |
uint16_t len = decode16(d, i); |
uint16_t len = decode16(d, i); |
762 |
768 |
char s[len * 4 + 1]; |
char s[len * 4 + 1]; |
763 |
769 |
bin2hex_ascii(s, d + *i, len); *i = *i + len; |
bin2hex_ascii(s, d + *i, len); *i = *i + len; |
764 |
770 |
snprintf(value, sizeof(value), |
snprintf(value, sizeof(value), |
765 |
771 |
"%hu:str:'%s'", j + 1, s); |
"%hu:str:'%s'", j + 1, s); |
|
772 |
|
} else { |
|
773 |
|
snprintf(value, sizeof(value), |
|
774 |
|
"%hu:unk, ...", j + 1); |
|
775 |
|
do_break = 1; // we cannot continue |
766 |
776 |
} |
} |
767 |
777 |
|
|
768 |
778 |
len = 2 + strlen(value); |
len = 2 + strlen(value); |
|
... |
... |
static void decode_query_params(char *out, size_t out_size, |
773 |
783 |
strcat(out, value); |
strcat(out, value); |
774 |
784 |
add = ", "; |
add = ", "; |
775 |
785 |
rest -= len; |
rest -= len; |
|
786 |
|
|
|
787 |
|
if (do_break) |
|
788 |
|
break; |
776 |
789 |
} |
} |
777 |
790 |
|
|
778 |
791 |
strcat(out, "}"); |
strcat(out, "}"); |
|
... |
... |
static void decode_func(const uint32_t parent, unsigned char *d) |
1135 |
1148 |
bin2hex_ascii(q, d + i, q_len); i += q_len; |
bin2hex_ascii(q, d + i, q_len); i += q_len; |
1136 |
1149 |
if (type == 'r') { |
if (type == 'r') { |
1137 |
1150 |
uint64_t res = decode64(d, &i); |
uint64_t res = decode64(d, &i); |
|
1151 |
|
uint64_t rows = decode64(d, &i); |
|
1152 |
|
uint64_t aff = decode64(d, &i); |
1138 |
1153 |
if (res == 0) |
if (res == 0) |
1139 |
1154 |
snprintf(rest, sizeof(rest), " = nok"); |
snprintf(rest, sizeof(rest), " = nok"); |
1140 |
1155 |
else if (res == 1) |
else if (res == 1) |
1141 |
|
snprintf(rest, sizeof(rest), " = ok"); |
|
|
1156 |
|
snprintf(rest, sizeof(rest), " = ok [%lu rows, %ld aff]", |
|
1157 |
|
rows, aff); |
1142 |
1158 |
else |
else |
1143 |
|
snprintf(rest, sizeof(rest), " = 0x%lx", res); |
|
|
1159 |
|
snprintf(rest, sizeof(rest), |
|
1160 |
|
" = 0x%lx [%lu rows, %ld aff]", |
|
1161 |
|
res, rows, aff); |
1144 |
1162 |
} |
} |
1145 |
1163 |
sprintf(line, "(link=0x%lx, '%s')%s", link, q, rest); |
sprintf(line, "(link=0x%lx, '%s')%s", link, q, rest); |
1146 |
1164 |
} else if (strcmp(func, "mysqli_real_connect") == 0) { |
} else if (strcmp(func, "mysqli_real_connect") == 0) { |
|
... |
... |
static void decode_func(const uint32_t parent, unsigned char *d) |
1153 |
1171 |
if (type == 'r') |
if (type == 'r') |
1154 |
1172 |
decode_bool(" = ", rest, sizeof(rest), d, &i); |
decode_bool(" = ", rest, sizeof(rest), d, &i); |
1155 |
1173 |
sprintf(line, "(link=0x%lx, '%s', flags='%s')%s", link, cs, flags, rest); |
sprintf(line, "(link=0x%lx, '%s', flags='%s')%s", link, cs, flags, rest); |
|
1174 |
|
} else if (strcmp(func, "mysqli_stmt_bind_param") == 0) { |
|
1175 |
|
//char dump[4096]; bin2hex_ascii(dump, d + i, 128); fprintf(out, "DUMP[%s][%c]: %s\n", func, type, dump); |
|
1176 |
|
uint64_t stmt = decode64(d, &i); |
|
1177 |
|
unsigned short types_len = decode16(d, &i); |
|
1178 |
|
char types[types_len * 4 + 1]; |
|
1179 |
|
bin2hex_ascii(types, d + i, types_len); i += types_len; |
|
1180 |
|
if (type == 'r') |
|
1181 |
|
decode_bool(" = ", rest, sizeof(rest), d, &i); |
|
1182 |
|
sprintf(line, "(stmt=0x%lx, types='%s', ...)%s", |
|
1183 |
|
stmt, types, rest); |
1156 |
1184 |
} else if (strcmp(func, "mysqli_stmt_execute") == 0) { |
} else if (strcmp(func, "mysqli_stmt_execute") == 0) { |
1157 |
|
char dump[4096]; bin2hex_ascii(dump, d + i, 128); fprintf(out, "DUMP[%s][%c]: %s\n", func, type, dump); |
|
|
1185 |
|
//char dump[4096]; bin2hex_ascii(dump, d + i, 128); fprintf(out, "DUMP[%s][%c]: %s\n", func, type, dump); |
1158 |
1186 |
uint64_t stmt = decode64(d, &i); |
uint64_t stmt = decode64(d, &i); |
1159 |
1187 |
if (type == 'c') { |
if (type == 'c') { |
1160 |
1188 |
decode_query_params(rest, sizeof(rest), d, &i); |
decode_query_params(rest, sizeof(rest), d, &i); |
|
... |
... |
static void decode_func(const uint32_t parent, unsigned char *d) |
1162 |
1190 |
stmt, rest[0] ? ", " : "", rest); |
stmt, rest[0] ? ", " : "", rest); |
1163 |
1191 |
} else if (type == 'r') { |
} else if (type == 'r') { |
1164 |
1192 |
uint8_t ret = decode8(d, &i); |
uint8_t ret = decode8(d, &i); |
1165 |
|
if (ret == 1) |
|
1166 |
|
snprintf(rest, sizeof(rest), " = ok"); |
|
1167 |
|
else |
|
|
1193 |
|
if (ret == 1) { |
|
1194 |
|
uint64_t rows = decode64(d, &i); |
|
1195 |
|
uint64_t aff = decode64(d, &i); |
|
1196 |
|
snprintf(rest, sizeof(rest), |
|
1197 |
|
" = ok [%lu rows, %ld aff]", rows, aff); |
|
1198 |
|
} else { |
1168 |
1199 |
snprintf(rest, sizeof(rest), " = nok"); |
snprintf(rest, sizeof(rest), " = nok"); |
|
1200 |
|
} |
1169 |
1201 |
sprintf(line, "(stmt=0x%lx)%s", stmt, rest); |
sprintf(line, "(stmt=0x%lx)%s", stmt, rest); |
1170 |
1202 |
} |
} |
1171 |
1203 |
} else if (strcmp(func, "mysqli_stmt_prepare") == 0) { |
} else if (strcmp(func, "mysqli_stmt_prepare") == 0) { |