Change in libosmocore[master]: Add _buf() functions to bypass static string buffers

Harald Welte gerrit-no-reply at lists.osmocom.org
Mon Apr 8 07:31:38 UTC 2019


Harald Welte has submitted this change and it was merged. ( https://gerrit.osmocom.org/13310 )

Change subject: Add _buf() functions to bypass static string buffers
......................................................................

Add _buf() functions to bypass static string buffers

We have a number of static buffers in use in libosmo*.  This means
the related functions are not usable in a thread-safe way.  While
we so far don't have many multi-threaded programs in the osmocom
universe, the static buffers also prevent us from calling the same
e.g. string-ify function twice within a single printf() call.

Let's make sure there's an alternative function in all those cases,
where the user can pass in a caller-allocated buffer + size, and make
the 'classic' function with the static buffer a wrapper around that
_buf() variant.

Change-Id: Ibf85f79e93244f53b2684ff6f1095c5b41203e05
---
M include/osmocom/core/msgb.h
M include/osmocom/core/utils.h
M include/osmocom/gprs/gprs_ns.h
M include/osmocom/gsm/abis_nm.h
M include/osmocom/gsm/apn.h
M include/osmocom/gsm/gsm0808_utils.h
M include/osmocom/gsm/gsm23003.h
M include/osmocom/gsm/gsm48.h
M include/osmocom/gsm/gsm_utils.h
M include/osmocom/gsm/protocol/gsm_04_08.h
M include/osmocom/gsm/rsl.h
M include/osmocom/sim/sim.h
M src/gb/gprs_ns.c
M src/gb/libosmogb.map
M src/gsm/abis_nm.c
M src/gsm/apn.c
M src/gsm/gsm0808_utils.c
M src/gsm/gsm23003.c
M src/gsm/gsm48.c
M src/gsm/gsm_utils.c
M src/gsm/libosmogsm.map
M src/gsm/rsl.c
M src/msgb.c
M src/sim/core.c
M src/utils.c
25 files changed, 362 insertions(+), 118 deletions(-)

Approvals:
  Jenkins Builder: Verified
  Vadim Yanitskiy: Looks good to me, but someone else must approve
  Harald Welte: Looks good to me, approved



diff --git a/include/osmocom/core/msgb.h b/include/osmocom/core/msgb.h
index 5029225..0c51ce2 100644
--- a/include/osmocom/core/msgb.h
+++ b/include/osmocom/core/msgb.h
@@ -67,6 +67,7 @@
 extern void msgb_reset(struct msgb *m);
 uint16_t msgb_length(const struct msgb *msg);
 extern const char *msgb_hexdump(const struct msgb *msg);
+char *msgb_hexdump_buf(char *buf, size_t buf_len, const struct msgb *msg);
 extern int msgb_resize_area(struct msgb *msg, uint8_t *area,
 	int old_size, int new_size);
 extern struct msgb *msgb_copy(const struct msgb *msg, const char *name);
diff --git a/include/osmocom/core/utils.h b/include/osmocom/core/utils.h
index e3728cd..6a2b7d5 100644
--- a/include/osmocom/core/utils.h
+++ b/include/osmocom/core/utils.h
@@ -53,6 +53,7 @@
 
 int osmo_hexparse(const char *str, uint8_t *b, int max_len);
 
+char *osmo_ubit_dump_buf(char *buf, size_t buf_len, const uint8_t *bits, unsigned int len);
 char *osmo_ubit_dump(const uint8_t *bits, unsigned int len);
 char *osmo_hexdump(const unsigned char *buf, int len);
 char *osmo_hexdump_nospc(const unsigned char *buf, int len);
@@ -139,7 +140,7 @@
 const char *osmo_escape_str(const char *str, int len);
 char *osmo_escape_str_buf(const char *str, int in_len, char *buf, size_t bufsize);
 const char *osmo_quote_str(const char *str, int in_len);
-const char *osmo_quote_str_buf(const char *str, int in_len, char *buf, size_t bufsize);
+char *osmo_quote_str_buf(const char *str, int in_len, char *buf, size_t bufsize);
 
 uint32_t osmo_isqrt32(uint32_t x);
 
diff --git a/include/osmocom/gprs/gprs_ns.h b/include/osmocom/gprs/gprs_ns.h
index c62ef98..ed155ff 100644
--- a/include/osmocom/gprs/gprs_ns.h
+++ b/include/osmocom/gprs/gprs_ns.h
@@ -211,6 +211,8 @@
 
 /* Resturn peer info as string (NOTE: the buffer is allocated statically) */
 const char *gprs_ns_ll_str(const struct gprs_nsvc *nsvc);
+/* Return peer info in user-supplied buffer */
+char *gprs_ns_ll_str_buf(char *buf, size_t buf_len, const struct gprs_nsvc *nsvc);
 
 /* Copy the link layer info from other into nsvc */
 void gprs_ns_ll_copy(struct gprs_nsvc *nsvc, struct gprs_nsvc *other);
diff --git a/include/osmocom/gsm/abis_nm.h b/include/osmocom/gsm/abis_nm.h
index 823b5a4..788727c 100644
--- a/include/osmocom/gsm/abis_nm.h
+++ b/include/osmocom/gsm/abis_nm.h
@@ -42,6 +42,7 @@
 extern const struct tlv_definition abis_nm_att_tlvdef_ipa;
 
 const char *abis_nm_dump_foh(const struct abis_om_fom_hdr *foh);
+char *abis_nm_dump_foh_buf(char *buf, size_t buf_len, const struct abis_om_fom_hdr *foh);
 
 /*! write a human-readable OML header to the debug log
  *  \param[in] ss Logging sub-system
diff --git a/include/osmocom/gsm/apn.h b/include/osmocom/gsm/apn.h
index 288b229..7899bb2 100644
--- a/include/osmocom/gsm/apn.h
+++ b/include/osmocom/gsm/apn.h
@@ -11,11 +11,14 @@
 #define APN_MAXLEN	100
 
 char *osmo_apn_qualify(unsigned int mcc, unsigned int mnc, const char *ni);
+char *osmo_apn_qualify_buf(char *buf, size_t buf_len, unsigned int mcc, unsigned int mnc, const char *ni);
 
 /* Compose a string of the form '<ni>.mnc001.mcc002.gprs\0', returned in a
  * static buffer. */
 char *osmo_apn_qualify_from_imsi(const char *imsi,
 				 const char *ni, int have_3dig_mnc);
+char *osmo_apn_qualify_from_imsi_buf(char *buf, size_t buf_len, const char *imsi,
+				     const char *ni, int have_3dig_mnc);
 
 int osmo_apn_from_str(uint8_t *apn_enc, size_t max_apn_enc_len, const char *str);
 char *osmo_apn_to_str(char *out_str, const uint8_t *apn_enc, size_t apn_enc_len);
diff --git a/include/osmocom/gsm/gsm0808_utils.h b/include/osmocom/gsm/gsm0808_utils.h
index dedb029..e246967 100644
--- a/include/osmocom/gsm/gsm0808_utils.h
+++ b/include/osmocom/gsm/gsm0808_utils.h
@@ -69,7 +69,9 @@
 };
 
 char *osmo_lcls_dump(const struct osmo_lcls *lcls);
+char *osmo_lcls_dump_buf(char *buf, size_t buf_len, const struct osmo_lcls *lcls);
 char *osmo_gcr_dump(const struct osmo_lcls *lcls);
+char *osmo_gcr_dump_buf(char *buf, size_t buf_len, const struct osmo_lcls *lcls);
 
 extern const struct value_string gsm0808_cell_id_discr_names[];
 static inline const char *gsm0808_cell_id_discr_name(enum CELL_IDENT id_discr)
@@ -251,5 +253,6 @@
 }
 
 const char *gsm0808_channel_type_name(const struct gsm0808_channel_type *ct);
+char *gsm0808_channel_type_name_buf(char *buf, size_t buf_len, const struct gsm0808_channel_type *ct);
 
 /*! @} */
diff --git a/include/osmocom/gsm/gsm23003.h b/include/osmocom/gsm/gsm23003.h
index cf622ce..88c4f3c 100644
--- a/include/osmocom/gsm/gsm23003.h
+++ b/include/osmocom/gsm/gsm23003.h
@@ -105,13 +105,19 @@
 bool osmo_imei_str_valid(const char *imei, bool with_15th_digit);
 
 const char *osmo_mcc_name(uint16_t mcc);
+char *osmo_mcc_name_buf(char *buf, size_t buf_len, uint16_t mcc);
 const char *osmo_mnc_name(uint16_t mnc, bool mnc_3_digits);
+char *osmo_mnc_name_buf(char *buf, size_t buf_len, uint16_t mnc, bool mnc_3_digits);
 const char *osmo_plmn_name(const struct osmo_plmn_id *plmn);
 const char *osmo_plmn_name2(const struct osmo_plmn_id *plmn);
+char *osmo_plmn_name_buf(char *buf, size_t buf_len, const struct osmo_plmn_id *plmn);
 const char *osmo_lai_name(const struct osmo_location_area_id *lai);
+char *osmo_lai_name_buf(char *buf, size_t buf_len, const struct osmo_location_area_id *lai);
 const char *osmo_cgi_name(const struct osmo_cell_global_id *cgi);
 const char *osmo_cgi_name2(const struct osmo_cell_global_id *cgi);
+char *osmo_cgi_name_buf(char *buf, size_t buf_len, const struct osmo_cell_global_id *cgi);
 const char *osmo_gummei_name(const struct osmo_gummei *gummei);
+char *osmo_gummei_name_buf(char *buf, size_t buf_len, const struct osmo_gummei *gummei);
 
 void osmo_plmn_to_bcd(uint8_t *bcd_dst, const struct osmo_plmn_id *plmn);
 void osmo_plmn_from_bcd(const uint8_t *bcd_src, struct osmo_plmn_id *plmn);
diff --git a/include/osmocom/gsm/gsm48.h b/include/osmocom/gsm/gsm48.h
index 7e0e5c4..81b2bf0 100644
--- a/include/osmocom/gsm/gsm48.h
+++ b/include/osmocom/gsm/gsm48.h
@@ -35,6 +35,7 @@
 const char *gsm48_rr_msg_name(uint8_t msgtype);
 const char *rr_cause_name(uint8_t cause);
 const char *osmo_rai_name(const struct gprs_ra_id *rai);
+char *osmo_rai_name_buf(char *buf, size_t buf_len, const struct gprs_ra_id *rai);
 
 int gsm48_decode_lai(struct gsm48_loc_area_id *lai, uint16_t *mcc,
 		     uint16_t *mnc, uint16_t *lac)
@@ -55,6 +56,7 @@
 			const uint8_t *mi, const int mi_len);
 const char *gsm48_mi_type_name(uint8_t mi);
 const char *osmo_mi_name(const uint8_t *mi, uint8_t mi_len);
+char *osmo_mi_name_buf(char *buf, size_t buf_len, const uint8_t *mi, uint8_t mi_len);
 
 /* Parse Routeing Area Identifier */
 void gsm48_parse_ra(struct gprs_ra_id *raid, const uint8_t *buf);
diff --git a/include/osmocom/gsm/gsm_utils.h b/include/osmocom/gsm/gsm_utils.h
index f8f72a7..f48cc68 100644
--- a/include/osmocom/gsm/gsm_utils.h
+++ b/include/osmocom/gsm/gsm_utils.h
@@ -180,6 +180,7 @@
 
 /* Returns static buffer with string representation of a GSM Time */
 char *osmo_dump_gsmtime(const struct gsm_time *tm);
+char *osmo_dump_gsmtime_buf(char *buf, size_t buf_len, const struct gsm_time *tm);
 
 /* GSM TS 03.03 Chapter 2.6 */
 enum gprs_tlli_type {
diff --git a/include/osmocom/gsm/protocol/gsm_04_08.h b/include/osmocom/gsm/protocol/gsm_04_08.h
index c052e4c..c97df16 100644
--- a/include/osmocom/gsm/protocol/gsm_04_08.h
+++ b/include/osmocom/gsm/protocol/gsm_04_08.h
@@ -70,6 +70,7 @@
 bool osmo_gsm48_classmark2_is_r99(const struct gsm48_classmark2 *cm2, uint8_t cm2_len);
 int osmo_gsm48_classmark_supports_a5(const struct osmo_gsm48_classmark *cm, uint8_t a5);
 const char *osmo_gsm48_classmark_a5_name(const struct osmo_gsm48_classmark *cm);
+char *osmo_gsm48_classmark_a5_name_buf(char *buf, size_t buf_len, const struct osmo_gsm48_classmark *cm);
 void osmo_gsm48_classmark_update(struct osmo_gsm48_classmark *dst, const struct osmo_gsm48_classmark *src);
 
 /* Chapter 10.5.2.1b.3 */
@@ -1643,6 +1644,7 @@
 extern const struct value_string gsm48_mm_msgtype_names[];
 extern const struct value_string gsm48_cc_msgtype_names[];
 const char *gsm48_pdisc_msgtype_name(uint8_t pdisc, uint8_t msg_type);
+char *gsm48_pdisc_msgtype_name_buf(char *buf, size_t buf_len, uint8_t pdisc, uint8_t msg_type);
 
 /* FIXME: Table 10.4 / 10.4a (GPRS) */
 
diff --git a/include/osmocom/gsm/rsl.h b/include/osmocom/gsm/rsl.h
index be0fa79..4a1da3a 100644
--- a/include/osmocom/gsm/rsl.h
+++ b/include/osmocom/gsm/rsl.h
@@ -30,6 +30,7 @@
 /* decode channel number as per Section 9.3.1 */
 int rsl_dec_chan_nr(uint8_t chan_nr, uint8_t *type, uint8_t *subch, uint8_t *timeslot);
 /* Turns channel number into a string */
+char *rsl_chan_nr_str_buf(char *buf, size_t buf_len, uint8_t chan_nr);
 const char *rsl_chan_nr_str(uint8_t chan_nr);
 
 
diff --git a/include/osmocom/sim/sim.h b/include/osmocom/sim/sim.h
index 680cad1..0490dcd 100644
--- a/include/osmocom/sim/sim.h
+++ b/include/osmocom/sim/sim.h
@@ -296,6 +296,7 @@
 					uint16_t sw_in);
 
 struct osim_card_hdl;
+char *osim_print_sw_buf(char *buf, size_t buf_len, const struct osim_card_hdl *ch, uint16_t sw_in);
 char *osim_print_sw(const struct osim_card_hdl *ch, uint16_t sw_in);
 
 extern const struct tlv_definition ts102221_fcp_tlv_def;
diff --git a/src/gb/gprs_ns.c b/src/gb/gprs_ns.c
index c7ff78e..fc120ce 100644
--- a/src/gb/gprs_ns.c
+++ b/src/gb/gprs_ns.c
@@ -1525,17 +1525,15 @@
 	return rc;
 }
 
-const char *gprs_ns_ll_str(const struct gprs_nsvc *nsvc)
+char *gprs_ns_ll_str_buf(char *buf, size_t buf_len, const struct gprs_nsvc *nsvc)
 {
-	static char buf[80];
-
 	switch(nsvc->ll) {
 	case GPRS_NS_LL_UDP:
-		snprintf(buf, sizeof(buf), "%s:%u",
+		snprintf(buf, buf_len, "%s:%u",
 			 inet_ntoa(nsvc->ip.bts_addr.sin_addr), osmo_ntohs(nsvc->ip.bts_addr.sin_port));
 		break;
 	case GPRS_NS_LL_FR_GRE:
-		snprintf(buf, sizeof(buf), "%s:%u",
+		snprintf(buf, buf_len, "%s:%u",
 			 inet_ntoa(nsvc->frgre.bts_addr.sin_addr), osmo_ntohs(nsvc->frgre.bts_addr.sin_port));
 		break;
 	default:
@@ -1543,11 +1541,17 @@
 		break;
 	}
 
-	buf[sizeof(buf) - 1] = '\0';
+	buf[buf_len - 1] = '\0';
 
 	return buf;
 }
 
+const char *gprs_ns_ll_str(const struct gprs_nsvc *nsvc)
+{
+	static char buf[80];
+	return gprs_ns_ll_str_buf(buf, sizeof(buf), nsvc);
+}
+
 void gprs_ns_ll_copy(struct gprs_nsvc *nsvc, struct gprs_nsvc *other)
 {
 	nsvc->ll = other->ll;
diff --git a/src/gb/libosmogb.map b/src/gb/libosmogb.map
index 2ad3ff7..21929da 100644
--- a/src/gb/libosmogb.map
+++ b/src/gb/libosmogb.map
@@ -64,6 +64,7 @@
 gprs_ns_tx_unblock;
 gprs_ns_vty_init;
 gprs_ns_ll_str;
+gprs_ns_ll_str_buf;
 gprs_ns_ll_copy;
 gprs_ns_ll_clear;
 gprs_ns_msgb_alloc;
diff --git a/src/gsm/abis_nm.c b/src/gsm/abis_nm.c
index 49d05ba..e25fdd0 100644
--- a/src/gsm/abis_nm.c
+++ b/src/gsm/abis_nm.c
@@ -928,14 +928,19 @@
 	return GSM_PCHAN_NONE;
 }
 
-const char *abis_nm_dump_foh(const struct abis_om_fom_hdr *foh)
+char *abis_nm_dump_foh_buf(char *buf, size_t buf_len, const struct abis_om_fom_hdr *foh)
 {
-	static char foh_buf[128];
-	snprintf(foh_buf, sizeof(foh_buf), "OC=%s(%02x) INST=(%02x,%02x,%02x)",
+	snprintf(buf, buf_len, "OC=%s(%02x) INST=(%02x,%02x,%02x)",
 		get_value_string(abis_nm_obj_class_names, foh->obj_class),
 		foh->obj_class, foh->obj_inst.bts_nr, foh->obj_inst.trx_nr,
 		foh->obj_inst.ts_nr);
-	return foh_buf;
+	return buf;
+}
+
+const char *abis_nm_dump_foh(const struct abis_om_fom_hdr *foh)
+{
+	static char foh_buf[128];
+	return abis_nm_dump_foh_buf(foh_buf, sizeof(foh_buf), foh);
 }
 
 /* this is just for compatibility reasons, it is now a macro */
diff --git a/src/gsm/apn.c b/src/gsm/apn.c
index 2674663..4ab370c 100644
--- a/src/gsm/apn.c
+++ b/src/gsm/apn.c
@@ -32,17 +32,22 @@
 
 static char apn_strbuf[APN_MAXLEN+1];
 
-char *osmo_apn_qualify(unsigned int mcc, unsigned int mnc, const char *ni)
+char *osmo_apn_qualify_buf(char *buf, size_t buf_len, unsigned int mcc, unsigned int mnc, const char *ni)
 {
-	snprintf(apn_strbuf, sizeof(apn_strbuf)-1, APN_GPRS_FMT,
-		ni, mnc, mcc);
-	apn_strbuf[sizeof(apn_strbuf)-1] = '\0';
+	snprintf(buf, buf_len-1, APN_GPRS_FMT, ni, mnc, mcc);
+	buf[buf_len-1] = '\0';
 
-	return apn_strbuf;
+	return buf;
 }
 
-char *osmo_apn_qualify_from_imsi(const char *imsi,
-				 const char *ni, int have_3dig_mnc)
+char *osmo_apn_qualify(unsigned int mcc, unsigned int mnc, const char *ni)
+{
+	return osmo_apn_qualify_buf(apn_strbuf, sizeof(apn_strbuf), mcc, mnc, ni);
+}
+
+
+char *osmo_apn_qualify_from_imsi_buf(char *buf, size_t buf_len, const char *imsi,
+				     const char *ni, int have_3dig_mnc)
 {
 	char cbuf[3+1], nbuf[3+1];
 
@@ -56,7 +61,13 @@
 		strncpy(nbuf, imsi+3, 2);
 		nbuf[2] = '\0';
 	}
-	return osmo_apn_qualify(atoi(cbuf), atoi(nbuf), ni);
+	return osmo_apn_qualify_buf(buf, buf_len, atoi(cbuf), atoi(nbuf), ni);
+}
+
+char *osmo_apn_qualify_from_imsi(const char *imsi,
+				 const char *ni, int have_3dig_mnc)
+{
+	return osmo_apn_qualify_from_imsi_buf(apn_strbuf, sizeof(apn_strbuf), imsi, ni, have_3dig_mnc);
 }
 
 /**
diff --git a/src/gsm/gsm0808_utils.c b/src/gsm/gsm0808_utils.c
index e0cdaaf..52e4674 100644
--- a/src/gsm/gsm0808_utils.c
+++ b/src/gsm/gsm0808_utils.c
@@ -595,11 +595,13 @@
 static char dbuf[256];
 
 /*! Dump LCLS parameters (GCR excluded) into string for printing.
+ *  \param[out] buf caller-allocated output string buffer
+ *  \param[in] buf_len size of buf in bytes
  *  \param[in] lcls pointer to the struct to print.
  *  \returns string representation of LCLS or NULL on error. */
-char *osmo_lcls_dump(const struct osmo_lcls *lcls)
+char *osmo_lcls_dump_buf(char *buf, size_t buf_len, const struct osmo_lcls *lcls)
 {
-	struct osmo_strbuf s = { .buf = dbuf, .len = 256 };
+	struct osmo_strbuf s = { .buf = buf, .len = buf_len };
 
 	if (!lcls)
 		return NULL;
@@ -612,12 +614,22 @@
 	return dbuf;
 }
 
+/*! Dump LCLS parameters (GCR excluded) into static string buffer for printing.
+ *  \param[in] lcls pointer to the struct to print.
+ *  \returns string representation of LCLS in static buffer or NULL on error. */
+char *osmo_lcls_dump(const struct osmo_lcls *lcls)
+{
+	return osmo_lcls_dump_buf(dbuf, sizeof(dbuf), lcls);
+}
+
 /*! Dump GCR struct into string for printing.
+ *  \param[out] buf caller-allocated output string buffer
+ *  \param[in] buf_len size of buf in bytes
  *  \param[in] lcls pointer to the struct to print.
  *  \returns string representation of GCR or NULL on error. */
-char *osmo_gcr_dump(const struct osmo_lcls *lcls)
+char *osmo_gcr_dump_buf(char *buf, size_t buf_len, const struct osmo_lcls *lcls)
 {
-	struct osmo_strbuf s = { .buf = dbuf, .len = 256 };
+	struct osmo_strbuf s = { .buf = buf, .len = buf_len };
 
 	if (!lcls)
 		return NULL;
@@ -631,6 +643,15 @@
 	return dbuf;
 }
 
+/*! Dump GCR struct into static string buffer for printing.
+ *  \param[in] lcls pointer to the struct to print.
+ *  \returns string representation of GCR in static buffer or NULL on error. */
+char *osmo_gcr_dump(const struct osmo_lcls *lcls)
+{
+	return osmo_gcr_dump_buf(dbuf, sizeof(dbuf), lcls);
+}
+
+
 /*! Encode TS 08.08 Encryption Information IE
  *  \param[out] msg Message Buffer to which IE is to be appended
  *  \param[in] ei Encryption Information to be encoded
@@ -1838,13 +1859,18 @@
 #undef APPEND_STR
 #undef APPEND_CELL_ID_U
 
-const char *gsm0808_channel_type_name(const struct gsm0808_channel_type *ct)
+char *gsm0808_channel_type_name_buf(char *buf, size_t buf_len, const struct gsm0808_channel_type *ct)
 {
-	static char buf[128];
-	snprintf(buf, sizeof(buf), "ch_indctr=0x%x ch_rate_type=0x%x perm_spch=%s",
+	snprintf(buf, buf_len, "ch_indctr=0x%x ch_rate_type=0x%x perm_spch=%s",
 		 ct->ch_indctr, ct->ch_rate_type,
 		 osmo_hexdump(ct->perm_spch, ct->perm_spch_len));
 	return buf;
 }
 
+const char *gsm0808_channel_type_name(const struct gsm0808_channel_type *ct)
+{
+	static char buf[128];
+	return gsm0808_channel_type_name_buf(buf, sizeof(buf), ct);
+}
+
 /*! @} */
diff --git a/src/gsm/gsm23003.c b/src/gsm/gsm23003.c
index 720c09b..bbfe236 100644
--- a/src/gsm/gsm23003.c
+++ b/src/gsm/gsm23003.c
@@ -90,13 +90,37 @@
 }
 
 /*! Return MCC string as standardized 3-digit with leading zeros.
+ * \param[out] buf caller-allocated output buffer
+ * \param[in] buf_len size of buf in bytes
+ * \param[in] mcc  MCC value.
+ * \returns string in user-supplied output buffer
+ */
+char *osmo_mcc_name_buf(char *buf, size_t buf_len, uint16_t mcc)
+{
+	snprintf(buf, buf_len, "%03u", mcc);
+	return buf;
+}
+
+/*! Return MCC string as standardized 3-digit with leading zeros.
  * \param[in] mcc  MCC value.
  * \returns string in static buffer.
  */
 const char *osmo_mcc_name(uint16_t mcc)
 {
 	static char buf[8];
-	snprintf(buf, sizeof(buf), "%03u", mcc);
+	return osmo_mcc_name_buf(buf, sizeof(buf), mcc);
+}
+
+/*! Return MNC string as standardized 2- or 3-digit with leading zeros.
+ * \param[out] buf caller-allocated output buffer
+ * \param[in] buf_len size of buf in bytes
+ * \param[in] mnc  MNC value.
+ * \param[in] mnc_3_digits  True if an MNC should fill three digits, only has an effect if MNC < 100.
+ * \returns string in static buffer.
+ */
+char *osmo_mnc_name_buf(char *buf, size_t buf_len, uint16_t mnc, bool mnc_3_digits)
+{
+	snprintf(buf, buf_len, "%0*u", mnc_3_digits ? 3 : 2, mnc);
 	return buf;
 }
 
@@ -108,14 +132,21 @@
 const char *osmo_mnc_name(uint16_t mnc, bool mnc_3_digits)
 {
 	static char buf[8];
-	snprintf(buf, sizeof(buf), "%0*u", mnc_3_digits ? 3 : 2, mnc);
-	return buf;
+	return osmo_mnc_name_buf(buf, sizeof(buf), mnc, mnc_3_digits);
 }
 
-static inline void plmn_name(char *buf, size_t buflen, const struct osmo_plmn_id *plmn)
+/*! Return MCC-MNC string as standardized 3-digit-dash-2/3-digit with leading zeros.
+ * \param[out] buf caller-allocated output buffer
+ * \param[in] buf_len size of buf in bytes
+ * \param[in] plmn  MCC-MNC value.
+ * \returns string in static buffer.
+ */
+char *osmo_plmn_name_buf(char *buf, size_t buf_len, const struct osmo_plmn_id *plmn)
 {
-	snprintf(buf, buflen, "%s-%s", osmo_mcc_name(plmn->mcc),
-		 osmo_mnc_name(plmn->mnc, plmn->mnc_3_digits));
+	char mcc[8], mnc[8];
+	snprintf(buf, buf_len, "%s-%s", osmo_mcc_name_buf(mcc, sizeof(mcc), plmn->mcc),
+		 osmo_mnc_name_buf(mnc, sizeof(mnc), plmn->mnc, plmn->mnc_3_digits));
+	return buf;
 }
 
 /*! Return MCC-MNC string as standardized 3-digit-dash-2/3-digit with leading zeros.
@@ -125,10 +156,10 @@
 const char *osmo_plmn_name(const struct osmo_plmn_id *plmn)
 {
 	static char buf[16];
-	plmn_name(buf, sizeof(buf), plmn);
-	return buf;
+	return osmo_plmn_name_buf(buf, sizeof(buf), plmn);
 }
 
+
 /*! Same as osmo_plmn_name(), but returning in a different static buffer.
  * \param[in] plmn  MCC-MNC value.
  * \returns string in static buffer.
@@ -136,7 +167,19 @@
 const char *osmo_plmn_name2(const struct osmo_plmn_id *plmn)
 {
 	static char buf[16];
-	plmn_name(buf, sizeof(buf), plmn);
+	return osmo_plmn_name_buf(buf, sizeof(buf), plmn);
+}
+
+/*! Return MCC-MNC-LAC as string, in caller-provided output buffer.
+ * \param[out] buf caller-allocated output buffer
+ * \param[in] buf_len size of buf in bytes
+ * \param[in] lai  LAI to encode, the rac member is ignored.
+ * \returns buf
+ */
+char *osmo_lai_name_buf(char *buf, size_t buf_len, const struct osmo_location_area_id *lai)
+{
+	char plmn[16];
+	snprintf(buf, buf_len, "%s-%u", osmo_plmn_name_buf(plmn, sizeof(plmn), &lai->plmn), lai->lac);
 	return buf;
 }
 
@@ -147,13 +190,18 @@
 const char *osmo_lai_name(const struct osmo_location_area_id *lai)
 {
 	static char buf[32];
-	snprintf(buf, sizeof(buf), "%s-%u", osmo_plmn_name(&lai->plmn), lai->lac);
-	return buf;
+	return osmo_lai_name_buf(buf, sizeof(buf), lai);
 }
 
-static const char *_cgi_name(const struct osmo_cell_global_id *cgi, char *buf, size_t buflen)
+/*! Return MCC-MNC-LAC-CI as string, in caller-provided output buffer.
+ * \param[out] buf caller-allocated output buffer
+ * \param[in] buf_len size of buf in bytes
+ * \param[in] cgi  CGI to encode.
+ * \returns buf
+ */
+char *osmo_cgi_name_buf(char *buf, size_t buf_len, const struct osmo_cell_global_id *cgi)
 {
-	snprintf(buf, buflen, "%s-%u", osmo_lai_name(&cgi->lai), cgi->cell_identity);
+	snprintf(buf, buf_len, "%s-%u", osmo_lai_name(&cgi->lai), cgi->cell_identity);
 	return buf;
 }
 
@@ -164,7 +212,7 @@
 const char *osmo_cgi_name(const struct osmo_cell_global_id *cgi)
 {
 	static char buf[32];
-	return _cgi_name(cgi, buf, sizeof(buf));
+	return osmo_cgi_name_buf(buf, sizeof(buf), cgi);
 }
 
 /*! Same as osmo_cgi_name(), but uses a different static buffer.
@@ -175,7 +223,7 @@
 const char *osmo_cgi_name2(const struct osmo_cell_global_id *cgi)
 {
 	static char buf[32];
-	return _cgi_name(cgi, buf, sizeof(buf));
+	return osmo_cgi_name_buf(buf, sizeof(buf), cgi);
 }
 
 static void to_bcd(uint8_t *bcd, uint16_t val)
@@ -187,14 +235,31 @@
 	bcd[0] = val % 10;
 }
 
-const char *osmo_gummei_name(const struct osmo_gummei *gummei)
+/*! Return string representation of GUMMEI in caller-provided output buffer.
+ * \param[out] buf pointer to caller-provided output buffer
+ * \param[in] buf_len size of buf in bytes
+ * \param[in] gummei GUMMEI to be stringified
+ * \returns buf
+ */
+char *osmo_gummei_name_buf(char *buf, size_t buf_len, const struct osmo_gummei *gummei)
 {
-	static char buf[32];
-	snprintf(buf, sizeof(buf), "%s-%04x-%02x", osmo_plmn_name(&gummei->plmn),
+	char plmn[16];
+	snprintf(buf, buf_len, "%s-%04x-%02x", osmo_plmn_name_buf(plmn, sizeof(plmn), &gummei->plmn),
 		 gummei->mme.group_id, gummei->mme.code);
 	return buf;
 }
 
+/*! Return string representation of GUMMEI in static output buffer.
+ * \param[in] gummei GUMMEI to be stringified
+ * \returns pointer to static output buffer
+ */
+const char *osmo_gummei_name(const struct osmo_gummei *gummei)
+{
+	static char buf[32];
+	return osmo_gummei_name_buf(buf, sizeof(buf), gummei);
+}
+
+
 /* Convert MCC + MNC to BCD representation
  * \param[out] bcd_dst caller-allocated memory for output
  * \param[in] mcc Mobile Country Code
diff --git a/src/gsm/gsm48.c b/src/gsm/gsm48.c
index 5dc30ad..a45d67b 100644
--- a/src/gsm/gsm48.c
+++ b/src/gsm/gsm48.c
@@ -182,6 +182,20 @@
 	return get_value_string(rr_cause_names, cause);
 }
 
+/*! Return MCC-MNC-LAC-RAC as string, in a caller-provided output buffer.
+ * \param[out] buf caller-provided output buffer
+ * \param[in] buf_len size of buf in bytes
+ * \param[in] rai  RAI to encode.
+ * \returns buf
+ */
+char *osmo_rai_name_buf(char *buf, size_t buf_len, const struct gprs_ra_id *rai)
+{
+	snprintf(buf, buf_len, "%s-%s-%u-%u",
+		 osmo_mcc_name(rai->mcc), osmo_mnc_name(rai->mnc, rai->mnc_3_digits), rai->lac,
+		 rai->rac);
+	return buf;
+}
+
 /*! Return MCC-MNC-LAC-RAC as string, in a static buffer.
  * \param[in] rai  RAI to encode.
  * \returns Static string buffer.
@@ -189,10 +203,7 @@
 const char *osmo_rai_name(const struct gprs_ra_id *rai)
 {
 	static char buf[32];
-	snprintf(buf, sizeof(buf), "%s-%s-%u-%u",
-		 osmo_mcc_name(rai->mcc), osmo_mnc_name(rai->mnc, rai->mnc_3_digits), rai->lac,
-		 rai->rac);
-	return buf;
+	return osmo_rai_name_buf(buf, sizeof(buf), rai);
 }
 
 /* FIXME: convert to value_string */
@@ -433,14 +444,15 @@
 	return get_value_string(mi_type_names, mi);
 }
 
-/*! Return a human readable representation of a Mobile Identity in static buffer.
+/*! Return a human readable representation of a Mobile Identity in caller-provided buffer.
+ * \param[out] buf caller-provided output buffer
+ * \param[in] buf_len size of buf in bytes
  * \param[in] mi  Mobile Identity buffer containing 3GPP TS 04.08 style MI type and data.
  * \param[in] mi_len  Length of mi.
- * \return A string like "IMSI-1234567", "TMSI-0x1234ABCD" or "unknown", "TMSI-invalid"...
+ * \return buf
  */
-const char *osmo_mi_name(const uint8_t *mi, uint8_t mi_len)
+char *osmo_mi_name_buf(char *buf, size_t buf_len, const uint8_t *mi, uint8_t mi_len)
 {
-	static char mi_name[10 + GSM48_MI_SIZE + 1];
 	uint8_t mi_type;
 	uint32_t tmsi;
 	char mi_string[GSM48_MI_SIZE];
@@ -452,8 +464,8 @@
 		/* Table 10.5.4.3, reverse generate_mid_from_tmsi */
 		if (mi_len == GSM48_TMSI_LEN && mi[0] == (0xf0 | GSM_MI_TYPE_TMSI)) {
 			tmsi = osmo_load32be(&mi[1]);
-			snprintf(mi_name, sizeof(mi_name), "TMSI-0x%08" PRIX32, tmsi);
-			return mi_name;
+			snprintf(buf, buf_len, "TMSI-0x%08" PRIX32, tmsi);
+			return buf;
 		}
 		return "TMSI-invalid";
 
@@ -461,14 +473,25 @@
 	case GSM_MI_TYPE_IMEI:
 	case GSM_MI_TYPE_IMEISV:
 		osmo_bcd2str(mi_string, sizeof(mi_string), mi, 1, (mi_len * 2) - (mi[0] & GSM_MI_ODD ? 0 : 1), true);
-		snprintf(mi_name, sizeof(mi_name), "%s-%s", gsm48_mi_type_name(mi_type), mi_string);
-		return mi_name;
+		snprintf(buf, buf_len, "%s-%s", gsm48_mi_type_name(mi_type), mi_string);
+		return buf;
 
 	default:
 		return "unknown";
 	}
 }
 
+/*! Return a human readable representation of a Mobile Identity in static buffer.
+ * \param[in] mi  Mobile Identity buffer containing 3GPP TS 04.08 style MI type and data.
+ * \param[in] mi_len  Length of mi.
+ * \return A string like "IMSI-1234567", "TMSI-0x1234ABCD" or "unknown", "TMSI-invalid"...
+ */
+const char *osmo_mi_name(const uint8_t *mi, uint8_t mi_len)
+{
+	static char mi_name[10 + GSM48_MI_SIZE + 1];
+	return osmo_mi_name_buf(mi_name, sizeof(mi_name), mi, mi_len);
+}
+
 /*! Checks is particular message is cipherable in A/Gb mode according to
  *         3GPP TS 24.008 § 4.7.1.2
  *  \param[in] hdr Message header
@@ -1050,16 +1073,17 @@
 	{ 0, NULL }
 };
 
-/*! Compose a string naming the message type for given protocol.
+/*! Compose a string naming the message type for given protocol, in a caller-provided buffer.
  * If the message type string is known, return the message type name, otherwise
  * return "<protocol discriminator name>:<message type in hex>".
+ * \param[out] buf caller-allcated output string buffer
+ * \param[in] buf_len size of buf in bytes
  * \param[in] pdisc protocol discriminator like GSM48_PDISC_MM
  * \param[in] msg_type message type like GSM48_MT_MM_LOC_UPD_REQUEST
- * \returns statically allocated string or string constant.
+ * \returns buf
  */
-const char *gsm48_pdisc_msgtype_name(uint8_t pdisc, uint8_t msg_type)
+char *gsm48_pdisc_msgtype_name_buf(char *buf, size_t buf_len, uint8_t pdisc, uint8_t msg_type)
 {
-	static char namebuf[64];
 	const struct value_string *msgt_names;
 
 	switch (pdisc) {
@@ -1081,11 +1105,23 @@
 	}
 
 	if (msgt_names)
-		return get_value_string(msgt_names, msg_type);
+		snprintf(buf, buf_len, "%s", get_value_string(msgt_names, msg_type));
+	else
+		snprintf(buf, buf_len, "%s:0x%02x", gsm48_pdisc_name(pdisc), msg_type);
+	return buf;
+}
 
-	snprintf(namebuf, sizeof(namebuf), "%s:0x%02x",
-		 gsm48_pdisc_name(pdisc), msg_type);
-	return namebuf;
+/*! Compose a string naming the message type for given protocol, in a static buffer.
+ * If the message type string is known, return the message type name, otherwise
+ * return "<protocol discriminator name>:<message type in hex>".
+ * \param[in] pdisc protocol discriminator like GSM48_PDISC_MM
+ * \param[in] msg_type message type like GSM48_MT_MM_LOC_UPD_REQUEST
+ * \returns statically allocated string or string constant.
+ */
+const char *gsm48_pdisc_msgtype_name(uint8_t pdisc, uint8_t msg_type)
+{
+	static char namebuf[64];
+	return gsm48_pdisc_msgtype_name_buf(namebuf, sizeof(namebuf), pdisc, msg_type);
 }
 
 const struct value_string gsm48_reject_value_names[] = {
@@ -1187,9 +1223,8 @@
  * \param[in] cm  Classmarks.
  * \returns A statically allocated string like "cm1{a5/1=supported} cm2{0x23= A5/2 A5/3} no-cm3"
  */
-const char *osmo_gsm48_classmark_a5_name(const struct osmo_gsm48_classmark *cm)
+char *osmo_gsm48_classmark_a5_name_buf(char *buf, size_t buf_len, const struct osmo_gsm48_classmark *cm)
 {
-	static char buf[128];
 	char cm1[42] = "no-cm1";
 	char cm2[42] = " no-cm2";
 	char cm3[42] = " no-cm3";
@@ -1212,10 +1247,21 @@
 			 cm->classmark3[0] & (1 << 2) ? " A5/6" : "",
 			 cm->classmark3[0] & (1 << 3) ? " A5/7" : "");
 
-	snprintf(buf, sizeof(buf), "%s%s%s", cm1, cm2, cm3);
+	snprintf(buf, buf_len, "%s%s%s", cm1, cm2, cm3);
 	return buf;
 }
 
+/*! Return a string representation of A5 cipher algorithms indicated by Classmark 1, 2 and 3.
+ * \param[in] cm  Classmarks.
+ * \returns A statically allocated string like "cm1{a5/1=supported} cm2{0x23= A5/2 A5/3} no-cm3"
+ */
+const char *osmo_gsm48_classmark_a5_name(const struct osmo_gsm48_classmark *cm)
+{
+	static char buf[128];
+	return osmo_gsm48_classmark_a5_name_buf(buf, sizeof(buf), cm);
+}
+
+
 /*! Overwrite dst with the Classmark information present in src.
  * Add an new Classmark and overwrite in dst what src has to offer, but where src has no Classmark information, leave
  * dst unchanged. (For Classmark 2 and 3, dst will exactly match any non-zero Classmark length from src, hence may end
diff --git a/src/gsm/gsm_utils.c b/src/gsm/gsm_utils.c
index c9c15d5..f34d9ea 100644
--- a/src/gsm/gsm_utils.c
+++ b/src/gsm/gsm_utils.c
@@ -886,16 +886,21 @@
 	return (51 * ((time->t3 - time->t2 + 26) % 26) + time->t3 + (26 * 51 * time->t1));
 }
 
-char *osmo_dump_gsmtime(const struct gsm_time *tm)
+char *osmo_dump_gsmtime_buf(char *buf, size_t buf_len, const struct gsm_time *tm)
 {
-	static char buf[64];
-
-	snprintf(buf, sizeof(buf), "%06"PRIu32"/%02"PRIu16"/%02"PRIu8"/%02"PRIu8"/%02"PRIu8,
+	snprintf(buf, buf_len, "%06"PRIu32"/%02"PRIu16"/%02"PRIu8"/%02"PRIu8"/%02"PRIu8,
 		 tm->fn, tm->t1, tm->t2, tm->t3, (uint8_t)tm->fn%52);
 	buf[sizeof(buf)-1] = '\0';
 	return buf;
 }
 
+char *osmo_dump_gsmtime(const struct gsm_time *tm)
+{
+	static char buf[64];
+	return osmo_dump_gsmtime_buf(buf, sizeof(buf), tm);
+}
+
+
 /*! append range1024 encoded data to bit vector
  *  \param[out] bv Caller-provided output bit-vector
  *  \param[in] r Input Range1024 sructure */
diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map
index 3fadc5a..a69fb60 100644
--- a/src/gsm/libosmogsm.map
+++ b/src/gsm/libosmogsm.map
@@ -9,6 +9,7 @@
 abis_nm_chcomb4pchan;
 abis_nm_debugp_foh;
 abis_nm_dump_foh;
+abis_nm_dump_foh_buf;
 abis_nm_event_type_name;
 abis_nm_nack_cause_name;
 abis_nm_nack_name;
@@ -225,6 +226,7 @@
 gsm0808_permitted_speech_names;
 gsm0808_chosen_enc_alg_names;
 gsm0808_channel_type_name;
+gsm0808_channel_type_name_buf;
 gsm0808_lcls_config_names;
 gsm0808_lcls_control_names;
 gsm0808_lcls_status_names;
@@ -250,7 +252,9 @@
 osmo_dec_gcr;
 osmo_gcr_eq;
 osmo_gcr_dump;
+osmo_gcr_dump_buf;
 osmo_lcls_dump;
+osmo_lcls_dump_buf;
 
 gsm0858_rsl_ul_meas_enc;
 
@@ -345,6 +349,7 @@
 gsm48_dtx_mode;
 gsm48_mi_type_name;
 osmo_mi_name;
+osmo_mi_name_buf;
 gsm48_mcc_mnc_to_bcd;
 gsm48_mcc_mnc_from_bcd;
 gsm48_generate_lai2;
@@ -354,14 +359,21 @@
 osmo_plmn_to_bcd;
 osmo_plmn_from_bcd;
 osmo_mcc_name;
+osmo_mcc_name_buf;
 osmo_mnc_name;
+osmo_mnc_name_buf;
 osmo_plmn_name;
+osmo_plmn_name_buf;
 osmo_plmn_name2;
 osmo_lai_name;
+osmo_lai_name_buf;
 osmo_rai_name;
+osmo_rai_name_buf;
 osmo_cgi_name;
+osmo_cgi_name_buf;
 osmo_cgi_name2;
 osmo_gummei_name;
+osmo_gummei_name_buf;
 osmo_mnc_from_str;
 osmo_mnc_cmp;
 osmo_plmn_cmp;
@@ -378,6 +390,7 @@
 gsm48_cc_msgtype_names;
 gsm48_cc_cause_names;
 gsm48_pdisc_msgtype_name;
+gsm48_pdisc_msgtype_name_buf;
 gsm48_reject_value_names;
 
 gsm_7bit_decode;
@@ -403,6 +416,7 @@
 gsm_get_octet_len;
 gsm_gsmtime2fn;
 osmo_dump_gsmtime;
+osmo_dump_gsmtime_buf;
 
 gsm_milenage;
 gsm_septet_encode;
@@ -472,6 +486,7 @@
 rsl_ccch_conf_to_bs_cc_chans;
 rsl_ccch_conf_to_bs_ccch_sdcch_comb;
 rsl_chan_nr_str;
+rsl_chan_nr_str_buf;
 rsl_dec_chan_nr;
 rsl_enc_chan_nr;
 rsl_err_name;
@@ -533,7 +548,9 @@
 ipa_send;
 
 osmo_apn_qualify;
+osmo_apn_qualify_buf;
 osmo_apn_qualify_from_imsi;
+osmo_apn_qualify_from_imsi_buf;
 osmo_apn_to_str;
 osmo_apn_from_str;
 
@@ -592,6 +609,7 @@
 osmo_gsm48_classmark2_is_r99;
 osmo_gsm48_classmark_supports_a5;
 osmo_gsm48_classmark_a5_name;
+osmo_gsm48_classmark_a5_name_buf;
 osmo_gsm48_classmark_update;
 
 local: *;
diff --git a/src/gsm/rsl.c b/src/gsm/rsl.c
index e610ebf..7bc6002 100644
--- a/src/gsm/rsl.c
+++ b/src/gsm/rsl.c
@@ -215,33 +215,47 @@
 	return 0;
 }
 
-/*! Get human-readable string for RSL channel number */
-const char *rsl_chan_nr_str(uint8_t chan_nr)
+/*! Get human-readable string for RSL channel number, in caller-provided buffer.
+ *  \param[out] buf caller-provided output buffer
+ *  \param[in] buf_len size of buf in bytes
+ *  \param[in] chan_nr channel number to be stringified
+ *  \returns buf with string
+ */
+char *rsl_chan_nr_str_buf(char *buf, size_t buf_len, uint8_t chan_nr)
 {
-	static char str[20];
 	int ts = chan_nr & 7;
 	uint8_t cbits = chan_nr >> 3;
 
 	if (cbits == 0x01)
-		sprintf(str, "TCH/F on TS%d", ts);
+		snprintf(buf, buf_len, "TCH/F on TS%d", ts);
 	else if ((cbits & 0x1e) == 0x02)
-		sprintf(str, "TCH/H(%u) on TS%d", cbits & 0x01, ts);
+		snprintf(buf, buf_len, "TCH/H(%u) on TS%d", cbits & 0x01, ts);
 	else if ((cbits & 0x1c) == 0x04)
-		sprintf(str, "SDCCH/4(%u) on TS%d", cbits & 0x03, ts);
+		snprintf(buf, buf_len, "SDCCH/4(%u) on TS%d", cbits & 0x03, ts);
 	else if ((cbits & 0x18) == 0x08)
-		sprintf(str, "SDCCH/8(%u) on TS%d", cbits & 0x07, ts);
+		snprintf(buf, buf_len, "SDCCH/8(%u) on TS%d", cbits & 0x07, ts);
 	else if (cbits == 0x10)
-		sprintf(str, "BCCH on TS%d", ts);
+		snprintf(buf, buf_len, "BCCH on TS%d", ts);
 	else if (cbits == 0x11)
-		sprintf(str, "RACH on TS%d", ts);
+		snprintf(buf, buf_len, "RACH on TS%d", ts);
 	else if (cbits == 0x12)
-		sprintf(str, "PCH/AGCH on TS%d", ts);
+		snprintf(buf, buf_len, "PCH/AGCH on TS%d", ts);
 	else if (cbits == 0x18)
-		sprintf(str, "PDCH on TS%d", ts);
+		snprintf(buf, buf_len, "PDCH on TS%d", ts);
 	else
-		sprintf(str, "UNKNOWN on TS%d", ts);
+		snprintf(buf, buf_len, "UNKNOWN on TS%d", ts);
 
-        return str;
+        return buf;
+}
+
+/*! Get human-readable string for RSL channel number, in static buffer.
+ *  \param[in] chan_nr channel number to be stringified
+ *  \returns buf with string
+ */
+const char *rsl_chan_nr_str(uint8_t chan_nr)
+{
+	static char str[20];
+	return rsl_chan_nr_str_buf(str, sizeof(str), chan_nr);
 }
 
 static const struct value_string rsl_err_vals[] = {
diff --git a/src/msgb.c b/src/msgb.c
index ce7654a..47b413b 100644
--- a/src/msgb.c
+++ b/src/msgb.c
@@ -392,13 +392,14 @@
 }
 
 
-/*! Return a (static) buffer containing a hexdump of the msg
- * \param[in] msg message buffer
- * \returns a pointer to a static char array
+/*! fill user-provided buffer with hexdump of the msg.
+ * \param[out] buf caller-allocated buffer for output string
+ * \param[in] buf_len length of buf
+ * \param[in] msg message buffer to be dumped
+ * \returns buf
  */
-const char *msgb_hexdump(const struct msgb *msg)
+char *msgb_hexdump_buf(char *buf, size_t buf_len, const struct msgb *msg)
 {
-	static char buf[4100];
 	int buf_offs = 0;
 	int nchars;
 	const unsigned char *start = msg->data;
@@ -421,32 +422,32 @@
 		if (lxhs[i] > msg->tail)
 			continue;
 		if (lxhs[i] < msg->data || lxhs[i] > msg->tail) {
-			nchars = snprintf(buf + buf_offs, sizeof(buf) - buf_offs,
+			nchars = snprintf(buf + buf_offs, buf_len - buf_offs,
 					  "(L%d=data%+" PRIdPTR ") ",
 					  i+1, lxhs[i] - msg->data);
 			buf_offs += nchars;
 			continue;
 		}
 		if (lxhs[i] < start) {
-			nchars = snprintf(buf + buf_offs, sizeof(buf) - buf_offs,
+			nchars = snprintf(buf + buf_offs, buf_len - buf_offs,
 					  "(L%d%+" PRIdPTR ") ", i+1,
 					  start - lxhs[i]);
 			buf_offs += nchars;
 			continue;
 		}
-		nchars = snprintf(buf + buf_offs, sizeof(buf) - buf_offs,
+		nchars = snprintf(buf + buf_offs, buf_len - buf_offs,
 				  "%s[L%d]> ",
 				  osmo_hexdump(start, lxhs[i] - start),
 				  i+1);
-		if (nchars < 0 || nchars + buf_offs >= sizeof(buf))
+		if (nchars < 0 || nchars + buf_offs >= buf_len)
 			return "ERROR";
 
 		buf_offs += nchars;
 		start = lxhs[i];
 	}
-	nchars = snprintf(buf + buf_offs, sizeof(buf) - buf_offs,
+	nchars = snprintf(buf + buf_offs, buf_len - buf_offs,
 			  "%s", osmo_hexdump(start, msg->tail - start));
-	if (nchars < 0 || nchars + buf_offs >= sizeof(buf))
+	if (nchars < 0 || nchars + buf_offs >= buf_len)
 		return "ERROR";
 
 	buf_offs += nchars;
@@ -456,17 +457,17 @@
 			continue;
 
 		if (lxhs[i] < msg->head || lxhs[i] > msg->head + msg->data_len) {
-			nchars = snprintf(buf + buf_offs, sizeof(buf) - buf_offs,
+			nchars = snprintf(buf + buf_offs, buf_len - buf_offs,
 					  "(L%d out of range) ", i+1);
 		} else if (lxhs[i] <= msg->data + msg->data_len &&
 			   lxhs[i] > msg->tail) {
-			nchars = snprintf(buf + buf_offs, sizeof(buf) - buf_offs,
+			nchars = snprintf(buf + buf_offs, buf_len - buf_offs,
 					  "(L%d=tail%+" PRIdPTR ") ",
 					  i+1, lxhs[i] - msg->tail);
 		} else
 			continue;
 
-		if (nchars < 0 || nchars + buf_offs >= sizeof(buf))
+		if (nchars < 0 || nchars + buf_offs >= buf_len)
 			return "ERROR";
 		buf_offs += nchars;
 	}
@@ -474,6 +475,15 @@
 	return buf;
 }
 
+/*! Return a (static) buffer containing a hexdump of the msg.
+ * \param[in] msg message buffer
+ * \returns a pointer to a static char array
+ */
+const char *msgb_hexdump(const struct msgb *msg)
+{
+	static char buf[4100];
+	return msgb_hexdump_buf(buf, sizeof(buf), msg);
+}
 
 /*! Print a string to the end of message buffer.
  * \param[in] msgb message buffer.
diff --git a/src/sim/core.c b/src/sim/core.c
index a78cecc..998e836 100644
--- a/src/sim/core.c
+++ b/src/sim/core.c
@@ -267,10 +267,8 @@
 	return msg;
 }
 
-/* FIXME: do we want to mark this as __thread? */
-static char sw_print_buf[256];
 
-char *osim_print_sw(const struct osim_card_hdl *ch, uint16_t sw_in)
+char *osim_print_sw_buf(char *buf, size_t buf_len, const struct osim_card_hdl *ch, uint16_t sw_in)
 {
 	const struct osim_card_sw *csw;
 
@@ -283,25 +281,29 @@
 
 	switch (csw->type) {
 	case SW_TYPE_STR:
-		snprintf(sw_print_buf, sizeof(sw_print_buf),
-			 "%04x (%s)", sw_in, csw->u.str);
+		snprintf(buf, buf_len, "%04x (%s)", sw_in, csw->u.str);
 		break;
 	default:
 		goto ret_def;
 	}
 
-	sw_print_buf[sizeof(sw_print_buf)-1] = '\0';
+	buf[buf_len-1] = '\0';
 
-	return sw_print_buf;
+	return buf;
 
 ret_def:
-	snprintf(sw_print_buf, sizeof(sw_print_buf),
-		 "%04x (Unknown)", sw_in);
-	sw_print_buf[sizeof(sw_print_buf)-1] = '\0';
+	snprintf(buf, buf_len, "%04x (Unknown)", sw_in);
+	buf[buf_len-1] = '\0';
 
-	return sw_print_buf;
+	return buf;
 }
 
+char *osim_print_sw(const struct osim_card_hdl *ch, uint16_t sw_in)
+{
+	/* FIXME: do we want to mark this as __thread? */
+	static char sw_print_buf[256];
+	return osim_print_sw_buf(sw_print_buf, sizeof(sw_print_buf), ch, sw_in);
+}
 
 const struct osim_card_sw *osim_find_sw(const struct osim_card_profile *cp,
 					uint16_t sw_in)
diff --git a/src/utils.c b/src/utils.c
index 019e733..4796365 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -273,17 +273,20 @@
 	return out_buf;
 }
 
-/*! Convert a sequence of unpacked bits to ASCII string
+/*! Convert a sequence of unpacked bits to ASCII string, in user-supplied buffer.
+ * \param[out] buf caller-provided output string buffer
+ * \param[out] buf_len size of buf in bytes
  * \param[in] bits A sequence of unpacked bits
  * \param[in] len Length of bits
+ * \returns string representation in static buffer.
  */
-char *osmo_ubit_dump(const uint8_t *bits, unsigned int len)
+char *osmo_ubit_dump_buf(char *buf, size_t buf_len, const uint8_t *bits, unsigned int len)
 {
 	int i;
 
-	if (len > sizeof(hexd_buff)-1)
-		len = sizeof(hexd_buff)-1;
-	memset(hexd_buff, 0, sizeof(hexd_buff));
+	if (len > buf_len-1)
+		len = buf_len-1;
+	memset(buf, 0, buf_len);
 
 	for (i = 0; i < len; i++) {
 		char outch;
@@ -301,10 +304,20 @@
 			outch = 'E';
 			break;
 		}
-		hexd_buff[i] = outch;
+		buf[i] = outch;
 	}
-	hexd_buff[sizeof(hexd_buff)-1] = 0;
-	return hexd_buff;
+	buf[buf_len-1] = 0;
+	return buf;
+}
+
+/*! Convert a sequence of unpacked bits to ASCII string, in static buffer.
+ * \param[in] bits A sequence of unpacked bits
+ * \param[in] len Length of bits
+ * \returns string representation in static buffer.
+ */
+char *osmo_ubit_dump(const uint8_t *bits, unsigned int len)
+{
+	return osmo_ubit_dump_buf(hexd_buff, sizeof(hexd_buff), bits, len);
 }
 
 /*! Convert binary sequence to hexadecimal ASCII string
@@ -632,7 +645,7 @@
  * \param[in] in_len  Pass -1 to print until nul char, or >= 0 to force a length.
  * \returns buf containing a quoted and escaped representation, possibly truncated.
  */
-const char *osmo_quote_str_buf(const char *str, int in_len, char *buf, size_t bufsize)
+char *osmo_quote_str_buf(const char *str, int in_len, char *buf, size_t bufsize)
 {
 	int l;
 	if (!str)

-- 
To view, visit https://gerrit.osmocom.org/13310
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: libosmocore
Gerrit-Branch: master
Gerrit-MessageType: merged
Gerrit-Change-Id: Ibf85f79e93244f53b2684ff6f1095c5b41203e05
Gerrit-Change-Number: 13310
Gerrit-PatchSet: 9
Gerrit-Owner: Harald Welte <laforge at gnumonks.org>
Gerrit-Reviewer: Harald Welte <laforge at gnumonks.org>
Gerrit-Reviewer: Jenkins Builder (1000002)
Gerrit-Reviewer: Max <suraev at alumni.ntnu.no>
Gerrit-Reviewer: Neels Hofmeyr <nhofmeyr at sysmocom.de>
Gerrit-Reviewer: Vadim Yanitskiy <axilirator at gmail.com>
Gerrit-CC: Pau Espin Pedrol <pespin at sysmocom.de>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20190408/4c1223a1/attachment.html>


More information about the gerrit-log mailing list