From 2d4663c1fd30c3e185c0c2fcad85adced2235c4e Mon Sep 17 00:00:00 2001
From: Heng Guo <heng.guo@windriver.com>
Date: Mon, 7 Mar 2022 14:24:36 +0800
Subject: [PATCH] babeltrace2: Handle negative clock offset

Refer to commit: 61cf588beae752e5ddfc60b6b5310f769ac9e852
In some cases, negative offset in clock is possible. But babeltrace 2
does not handle negative offset in clock.

So handle a signed value for the offset attribute like offset_s

Signed-off-by: Heng Guo <heng.guo@windriver.com>
---
 include/babeltrace2/trace-ir/clock-class.h    |  4 +-
 include/babeltrace2/util.h                    |  2 +-
 src/common/common.h                           |  2 +-
 src/lib/graph/iterator.c                      |  2 +-
 src/lib/lib-logging.c                         |  2 +-
 src/lib/trace-ir/clock-class.c                |  7 ++-
 src/lib/trace-ir/clock-class.h                |  2 +-
 src/lib/trace-ir/utils.h                      | 44 +++++++------------
 src/lib/util.c                                |  4 +-
 src/plugins/ctf/common/metadata/ctf-meta.h    |  2 +-
 .../ctf/common/metadata/visitor-generate-ir.c | 16 +++----
 .../ctf/fs-sink/translate-ctf-ir-to-tsdl.c    |  4 +-
 .../debug-info/trace-ir-metadata-copy.c       |  2 +-
 src/plugins/text/details/write.c              |  2 +-
 src/plugins/utils/trimmer/trimmer.c           |  2 +-
 15 files changed, 41 insertions(+), 56 deletions(-)

diff --git a/include/babeltrace2/trace-ir/clock-class.h b/include/babeltrace2/trace-ir/clock-class.h
index f0685e39..66cf429c 100644
--- a/include/babeltrace2/trace-ir/clock-class.h
+++ b/include/babeltrace2/trace-ir/clock-class.h
@@ -423,7 +423,7 @@ See the \ref api-tir-clock-cls-prop-offset "offset" property.
     Returns the offset of a clock class.
 */
 extern void bt_clock_class_set_offset(bt_clock_class *clock_class,
-		int64_t offset_seconds, uint64_t offset_cycles);
+		int64_t offset_seconds, int64_t offset_cycles);
 
 /*!
 @brief
@@ -450,7 +450,7 @@ See the \ref api-tir-clock-cls-prop-offset "offset" property.
     Sets the offset of a clock class.
 */
 extern void bt_clock_class_get_offset(const bt_clock_class *clock_class,
-		int64_t *offset_seconds, uint64_t *offset_cycles);
+		int64_t *offset_seconds, int64_t *offset_cycles);
 
 /*!
 @brief
diff --git a/include/babeltrace2/util.h b/include/babeltrace2/util.h
index 6a76372d..f92ce762 100644
--- a/include/babeltrace2/util.h
+++ b/include/babeltrace2/util.h
@@ -137,7 +137,7 @@ code if any step of the computation process causes an integer overflow.
 bt_util_clock_cycles_to_ns_from_origin_status
 bt_util_clock_cycles_to_ns_from_origin(uint64_t cycles,
 		uint64_t frequency, int64_t offset_seconds,
-		uint64_t offset_cycles, int64_t *ns_from_origin);
+		int64_t offset_cycles, int64_t *ns_from_origin);
 
 /*! @} */
 
diff --git a/src/common/common.h b/src/common/common.h
index b5990a88..c06df786 100644
--- a/src/common/common.h
+++ b/src/common/common.h
@@ -733,7 +733,7 @@ const char *bt_common_func_status_string(int status)
 
 static inline
 int bt_common_clock_value_from_ns_from_origin(
-		int64_t cc_offset_seconds, uint64_t cc_offset_cycles,
+		int64_t cc_offset_seconds, int64_t cc_offset_cycles,
 		uint64_t cc_freq, int64_t ns_from_origin,
 		uint64_t *raw_value)
 {
diff --git a/src/lib/graph/iterator.c b/src/lib/graph/iterator.c
index 3f31f1a0..41f185f4 100644
--- a/src/lib/graph/iterator.c
+++ b/src/lib/graph/iterator.c
@@ -1631,7 +1631,7 @@ int clock_raw_value_from_ns_from_origin(const bt_clock_class *clock_class,
 {
 
 	int64_t cc_offset_s = clock_class->offset_seconds;
-	uint64_t cc_offset_cycles = clock_class->offset_cycles;
+	int64_t cc_offset_cycles = clock_class->offset_cycles;
 	uint64_t cc_freq = clock_class->frequency;
 
 	return bt_common_clock_value_from_ns_from_origin(cc_offset_s,
diff --git a/src/lib/lib-logging.c b/src/lib/lib-logging.c
index 2a10c68d..a5b45b31 100644
--- a/src/lib/lib-logging.c
+++ b/src/lib/lib-logging.c
@@ -822,7 +822,7 @@ static inline void format_clock_class(char **buf_ch, bool extended,
 
 	BUF_APPEND(", %sis-frozen=%d, %sprecision=%" PRIu64 ", "
 		"%soffset-s=%" PRId64 ", "
-		"%soffset-cycles=%" PRIu64 ", %sorigin-is-unix-epoch=%d, "
+		"%soffset-cycles=%" PRId64 ", %sorigin-is-unix-epoch=%d, "
 		"%sbase-offset-ns=%" PRId64,
 		PRFIELD(clock_class->frozen), PRFIELD(clock_class->precision),
 		PRFIELD(clock_class->offset_seconds),
diff --git a/src/lib/trace-ir/clock-class.c b/src/lib/trace-ir/clock-class.c
index 8a3640bc..0d898362 100644
--- a/src/lib/trace-ir/clock-class.c
+++ b/src/lib/trace-ir/clock-class.c
@@ -224,7 +224,7 @@ void bt_clock_class_set_precision(struct bt_clock_class *clock_class,
 }
 
 void bt_clock_class_get_offset(const struct bt_clock_class *clock_class,
-		int64_t *seconds, uint64_t *cycles)
+		int64_t *seconds, int64_t *cycles)
 {
 	BT_ASSERT_PRE_DEV_NON_NULL(clock_class, "Clock class");
 	BT_ASSERT_PRE_DEV_NON_NULL(seconds, "Seconds (output)");
@@ -234,17 +234,16 @@ void bt_clock_class_get_offset(const struct bt_clock_class *clock_class,
 }
 
 void bt_clock_class_set_offset(struct bt_clock_class *clock_class,
-		int64_t seconds, uint64_t cycles)
+		int64_t seconds, int64_t cycles)
 {
 	BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
 	BT_ASSERT_PRE_DEV_CLOCK_CLASS_HOT(clock_class);
-	BT_ASSERT_PRE(cycles < clock_class->frequency,
+	BT_ASSERT_PRE(llabs(cycles) < clock_class->frequency,
 		"Offset (cycles) is greater than clock class's frequency: "
 		"%![cc-]+K, new-offset-cycles=%" PRIu64, clock_class, cycles);
 	clock_class->offset_seconds = seconds;
 	clock_class->offset_cycles = cycles;
 	set_base_offset(clock_class);
-	BT_LIB_LOGD("Set clock class's offset: %!+K", clock_class);
 }
 
 bt_bool bt_clock_class_origin_is_unix_epoch(const struct bt_clock_class *clock_class)
diff --git a/src/lib/trace-ir/clock-class.h b/src/lib/trace-ir/clock-class.h
index 639cf90e..7e3a337d 100644
--- a/src/lib/trace-ir/clock-class.h
+++ b/src/lib/trace-ir/clock-class.h
@@ -62,7 +62,7 @@ struct bt_clock_class {
 	uint64_t frequency;
 	uint64_t precision;
 	int64_t offset_seconds;
-	uint64_t offset_cycles;
+	int64_t offset_cycles;
 
 	struct {
 		bt_uuid_t uuid;
diff --git a/src/lib/trace-ir/utils.h b/src/lib/trace-ir/utils.h
index a800808f..383c79de 100644
--- a/src/lib/trace-ir/utils.h
+++ b/src/lib/trace-ir/utils.h
@@ -36,20 +36,23 @@ struct search_query {
 };
 
 static inline
-uint64_t bt_util_ns_from_value(uint64_t frequency, uint64_t value_cycles)
+int64_t bt_util_ns_from_value(uint64_t frequency, uint64_t value_cycles)
 {
-	uint64_t ns;
+	int64_t ns;
 
 	if (frequency == UINT64_C(1000000000)) {
 		ns = value_cycles;
 	} else {
 		double dblres = ((1e9 * (double) value_cycles) / (double) frequency);
 
-		if (dblres >= (double) UINT64_MAX) {
-			/* Overflows uint64_t */
-			ns = UINT64_C(-1);
+		if (dblres >= (double) INT64_MAX) {
+			/* Overflows max int64_t */
+			ns = INT64_MAX;
+		} if (dblres <= (double) INT64_MIN) {
+			/* Overflows min int64_t */
+			ns = INT64_MIN;
 		} else {
-			ns = (uint64_t) dblres;
+			ns = (int64_t) dblres;
 		}
 	}
 
@@ -57,11 +60,11 @@ uint64_t bt_util_ns_from_value(uint64_t frequency, uint64_t value_cycles)
 }
 
 static inline
-bool bt_util_get_base_offset_ns(int64_t offset_seconds, uint64_t offset_cycles,
+bool bt_util_get_base_offset_ns(int64_t offset_seconds, int64_t offset_cycles,
 		uint64_t frequency, int64_t *base_offset_ns)
 {
 	bool overflows = false;
-	uint64_t offset_cycles_ns;
+	int64_t offset_cycles_ns;
 
 	BT_ASSERT_DBG(base_offset_ns);
 
@@ -83,10 +86,10 @@ bool bt_util_get_base_offset_ns(int64_t offset_seconds, uint64_t offset_cycles,
 	*base_offset_ns = offset_seconds * INT64_C(1000000000);
 
 	/* Add offset in cycles */
-	BT_ASSERT_DBG(offset_cycles < frequency);
+	BT_ASSERT_DBG(llabs(offset_cycles) < frequency);
 	offset_cycles_ns = bt_util_ns_from_value(frequency,
 		offset_cycles);
-	BT_ASSERT_DBG(offset_cycles_ns < 1000000000);
+	BT_ASSERT_DBG(llabs(offset_cycles_ns) < 1000000000);
 	*base_offset_ns += (int64_t) offset_cycles_ns;
 
 end:
@@ -95,33 +98,16 @@ end:
 
 static inline
 int bt_util_ns_from_origin_inline(int64_t base_offset_ns,
-		int64_t offset_seconds, uint64_t offset_cycles,
+		int64_t offset_seconds, int64_t offset_cycles,
 		uint64_t frequency, uint64_t value, int64_t *ns_from_origin)
 {
 	int ret = 0;
-	uint64_t value_ns_unsigned;
 	int64_t value_ns_signed;
 
 	/* Initialize to clock class's base offset */
 	*ns_from_origin = base_offset_ns;
-
 	/* Add given value in cycles */
-	value_ns_unsigned = bt_util_ns_from_value(frequency, value);
-	if (value_ns_unsigned >= (uint64_t) INT64_MAX) {
-		/*
-		 * FIXME: `value_ns_unsigned` could be greater than
-		 * `INT64_MAX` in fact: in this case, we need to
-		 * subtract `INT64_MAX` from `value_ns_unsigned`, make
-		 * sure that the difference is less than `INT64_MAX`,
-		 * and try to add them one after the other to
-		 * `*ns_from_origin`.
-		 */
-		ret = -1;
-		goto end;
-	}
-
-	value_ns_signed = (int64_t) value_ns_unsigned;
-	BT_ASSERT_DBG(value_ns_signed >= 0);
+	value_ns_signed = bt_util_ns_from_value(frequency, value);
 
 	if (*ns_from_origin <= 0) {
 		goto add_value;
diff --git a/src/lib/util.c b/src/lib/util.c
index 8c54e0ea..e6a42143 100644
--- a/src/lib/util.c
+++ b/src/lib/util.c
@@ -34,7 +34,7 @@
 bt_util_clock_cycles_to_ns_from_origin_status
 bt_util_clock_cycles_to_ns_from_origin(uint64_t cycles,
 		uint64_t frequency, int64_t offset_seconds,
-		uint64_t offset_cycles, int64_t *ns)
+		int64_t offset_cycles, int64_t *ns)
 {
 	bool overflows;
 	int64_t base_offset_ns;
@@ -46,7 +46,7 @@ bt_util_clock_cycles_to_ns_from_origin(uint64_t cycles,
 	BT_ASSERT_PRE_NON_NULL(ns, "Nanoseconds (output)");
 	BT_ASSERT_PRE(frequency != UINT64_C(-1) && frequency != 0,
 		"Invalid frequency: freq=%" PRIu64, frequency);
-	BT_ASSERT_PRE(offset_cycles < frequency,
+	BT_ASSERT_PRE(llabs(offset_cycles) < frequency,
 		"Offset (cycles) is greater than frequency: "
 		"offset-cycles=%" PRIu64 ", freq=%" PRIu64,
 		offset_cycles, frequency);
diff --git a/src/plugins/ctf/common/metadata/ctf-meta.h b/src/plugins/ctf/common/metadata/ctf-meta.h
index 3a5fec2d..b2b688a7 100644
--- a/src/plugins/ctf/common/metadata/ctf-meta.h
+++ b/src/plugins/ctf/common/metadata/ctf-meta.h
@@ -78,7 +78,7 @@ struct ctf_clock_class {
 	uint64_t frequency;
 	uint64_t precision;
 	int64_t offset_seconds;
-	uint64_t offset_cycles;
+	int64_t offset_cycles;
 	bt_uuid_t uuid;
 	bool has_uuid;
 	bool is_absolute;
diff --git a/src/plugins/ctf/common/metadata/visitor-generate-ir.c b/src/plugins/ctf/common/metadata/visitor-generate-ir.c
index 5f071ff7..c26aade4 100644
--- a/src/plugins/ctf/common/metadata/visitor-generate-ir.c
+++ b/src/plugins/ctf/common/metadata/visitor-generate-ir.c
@@ -4193,7 +4193,7 @@ error:
 static
 int visit_clock_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
 	struct ctf_clock_class *clock, int *set, int64_t *offset_seconds,
-	uint64_t *offset_cycles)
+	int64_t *offset_cycles)
 {
 	int ret = 0;
 	char *left = NULL;
@@ -4350,7 +4350,7 @@ int visit_clock_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
 			goto error;
 		}
 
-		ret = get_unary_unsigned(ctx,
+		ret = get_unary_signed(
 			&entry_node->u.ctf_expression.right, offset_cycles);
 		if (ret) {
 			_BT_COMP_LOGE_NODE(entry_node,
@@ -4415,10 +4415,10 @@ uint64_t cycles_from_ns(uint64_t frequency, uint64_t ns)
 
 static
 void calibrate_clock_class_offsets(int64_t *offset_seconds,
-		uint64_t *offset_cycles, uint64_t freq)
+		int64_t *offset_cycles, uint64_t freq)
 {
-	if (*offset_cycles >= freq) {
-		const uint64_t s_in_offset_cycles = *offset_cycles / freq;
+	if (llabs(*offset_cycles) >= freq) {
+		const int64_t s_in_offset_cycles = *offset_cycles / freq;
 
 		*offset_seconds += (int64_t) s_in_offset_cycles;
 		*offset_cycles -= (s_in_offset_cycles * freq);
@@ -4444,7 +4444,7 @@ void apply_clock_class_offset(struct ctx *ctx,
 	int64_t offset_s_to_apply = ctx->decoder_config.clock_class_offset_s;
 	uint64_t offset_ns_to_apply;
 	int64_t cur_offset_s;
-	uint64_t cur_offset_cycles;
+	int64_t cur_offset_cycles;
 
 	if (ctx->decoder_config.clock_class_offset_s == 0 &&
 			ctx->decoder_config.clock_class_offset_ns == 0) {
@@ -4505,7 +4505,7 @@ int visit_clock_decl(struct ctx *ctx, struct ctf_node *clock_node)
 	struct bt_list_head *decl_list = &clock_node->u.clock.declaration_list;
 	const char *clock_class_name;
 	int64_t offset_seconds = 0;
-	uint64_t offset_cycles = 0;
+	int64_t offset_cycles = 0;
 	uint64_t freq;
 
 	if (clock_node->visited) {
@@ -4559,7 +4559,7 @@ int visit_clock_decl(struct ctx *ctx, struct ctf_node *clock_node)
 	 */
 	freq = clock->frequency;
 	calibrate_clock_class_offsets(&offset_seconds, &offset_cycles, freq);
-	BT_ASSERT(offset_cycles < clock->frequency);
+	BT_ASSERT(llabs(offset_cycles) < clock->frequency);
 	clock->offset_seconds = offset_seconds;
 	clock->offset_cycles = offset_cycles;
 	apply_clock_class_offset(ctx, clock);
diff --git a/src/plugins/ctf/fs-sink/translate-ctf-ir-to-tsdl.c b/src/plugins/ctf/fs-sink/translate-ctf-ir-to-tsdl.c
index bfab450c..a7c00037 100644
--- a/src/plugins/ctf/fs-sink/translate-ctf-ir-to-tsdl.c
+++ b/src/plugins/ctf/fs-sink/translate-ctf-ir-to-tsdl.c
@@ -718,7 +718,7 @@ void append_stream_class(struct ctx *ctx,
 	if (sc->default_clock_class) {
 		const char *descr;
 		int64_t offset_seconds;
-		uint64_t offset_cycles;
+		int64_t offset_cycles;
 		bt_uuid uuid;
 
 		append_indent(ctx);
@@ -748,7 +748,7 @@ void append_stream_class(struct ctx *ctx,
 		g_string_append_printf(ctx->tsdl, "offset_s = %" PRId64 ";\n",
 			offset_seconds);
 		append_indent(ctx);
-		g_string_append_printf(ctx->tsdl, "offset = %" PRIu64 ";\n",
+		g_string_append_printf(ctx->tsdl, "offset = %" PRId64 ";\n",
 			offset_cycles);
 		append_indent(ctx);
 		g_string_append(ctx->tsdl, "absolute = ");
diff --git a/src/plugins/lttng-utils/debug-info/trace-ir-metadata-copy.c b/src/plugins/lttng-utils/debug-info/trace-ir-metadata-copy.c
index a31da24a..d99ce0c2 100644
--- a/src/plugins/lttng-utils/debug-info/trace-ir-metadata-copy.c
+++ b/src/plugins/lttng-utils/debug-info/trace-ir-metadata-copy.c
@@ -99,7 +99,7 @@ enum debug_info_trace_ir_mapping_status copy_clock_class_content(
 	enum debug_info_trace_ir_mapping_status status;
 	const char *clock_class_name, *clock_class_description;
 	int64_t seconds;
-	uint64_t cycles;
+	int64_t cycles;
 	bt_uuid in_uuid;
 
 	BT_COMP_LOGD("Copying content of clock class: in-cc-addr=%p, out-cc-addr=%p",
diff --git a/src/plugins/text/details/write.c b/src/plugins/text/details/write.c
index dfe77b86..e620c0dc 100644
--- a/src/plugins/text/details/write.c
+++ b/src/plugins/text/details/write.c
@@ -1350,7 +1350,7 @@ void write_clock_class_prop_lines(struct details_write_ctx *ctx,
 		const bt_clock_class *cc)
 {
 	int64_t offset_seconds;
-	uint64_t offset_cycles;
+	int64_t offset_cycles;
 	const char *str;
 
 	str = bt_clock_class_get_name(cc);
diff --git a/src/plugins/utils/trimmer/trimmer.c b/src/plugins/utils/trimmer/trimmer.c
index 9a8bffde..1f08a5c9 100644
--- a/src/plugins/utils/trimmer/trimmer.c
+++ b/src/plugins/utils/trimmer/trimmer.c
@@ -1122,7 +1122,7 @@ int clock_raw_value_from_ns_from_origin(const bt_clock_class *clock_class,
 {
 
 	int64_t cc_offset_s;
-	uint64_t cc_offset_cycles;
+	int64_t cc_offset_cycles;
 	uint64_t cc_freq;
 
 	bt_clock_class_get_offset(clock_class, &cc_offset_s, &cc_offset_cycles);
-- 
2.26.1

