Skip to content

Commit 3973d90

Browse files
author
Memfault Inc
committed
Memfault Firmware SDK 0.24.0 (Build 283912)
1 parent 907c880 commit 3973d90

32 files changed

+1068
-25
lines changed

CHANGES.md

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,31 @@
1+
### Changes between Memfault SDK 0.24.0 and SDK 0.23.0 - July 27, 2021
2+
3+
#### :chart_with_upwards_trend: Improvements
4+
5+
- Added "compact log" support to trace events. When enabled, the format string will be removed at
6+
compile time from calls to `MEMFAULT_TRACE_EVENT_WITH_LOG` and an integer along with arguments
7+
will be serialized instead. The actual string will recovered and formatted when it arrives in the
8+
Memfault cloud. This leads to a massive reduction in space & bandwidth needed to send trace
9+
events. For more details about how to set up,
10+
[check out this guide!](https://mflt.io/compact-logs)
11+
- Fixed a `-Wshadow` compiler error that would arise in
12+
[`memfault_coredump_regions_armv7.c`](components/panics/src/memfault_coredump_regions_armv7.c) when
13+
`MEMFAULT_COLLECT_MPU_STATE` was enabled
14+
- Updated debug print utility in
15+
[`memfault_coredump_storage_debug.c`](components/panics/src/memfault_coredump_storage_debug.c) to
16+
guard against potentially printing an uninitialized string.
17+
- Removed unnecessary extra argument from `MEMFAULT_SOFTWARE_WATCHDOG`
18+
19+
#### :boom: Breaking Changes
20+
21+
- If you were already using `MEMFAULT_SOFTWARE_WATCHDOG`, you will need to update your call site
22+
invocations to remove the argument being passed. i.e
23+
24+
```diff
25+
- MEMFAULT_SOFTWARE_WATCHDOG(0);
26+
+ MEMFAULT_SOFTWARE_WATCHDOG();
27+
```
28+
129
### Changes between Memfault SDK 0.23.0 and SDK 0.22.0 - July 8, 2021
230

331
#### :chart_with_upwards_trend: Improvements
@@ -1332,7 +1360,7 @@ void record_temperature(void) {
13321360
The feature can be disabled completely by adding
13331361
`-DMEMFAULT_COLLECT_INTERRUPT_STATE=0` to your compiler flags. More
13341362
configuration options can be found in
1335-
[memfault_coredump_regions_armv7.m](components/panics/src/memfault_coredump_regions_armv7.c).
1363+
[memfault_coredump_regions_armv7.c](components/panics/src/memfault_coredump_regions_armv7.c).
13361364
- Improve documentation about integrating the SDK within a project in README
13371365
- Update Release note summary to use markdown headings for easier referencing.
13381366
- Update try script used to collect coredumps via GDB to also collect

VERSION

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
BUILD ID: 268452
2-
GIT COMMIT: 9d1b0d8da
1+
BUILD ID: 283912
2+
GIT COMMIT: 7f6c0b54c
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
//! @file
2+
//!
3+
//! Copyright (c) Memfault, Inc.
4+
//! See License.txt for details
5+
6+
#include <stdarg.h>
7+
#include <stdio.h>
8+
#include <string.h>
9+
10+
#include "memfault/config.h"
11+
12+
#if MEMFAULT_COMPACT_LOG_ENABLE
13+
14+
#include "memfault/core/compiler.h"
15+
#include "memfault/core/debug_log.h"
16+
#include "memfault/core/compact_log_helpers.h"
17+
#include "memfault/core/compact_log_serializer.h"
18+
#include "memfault/util/cbor.h"
19+
20+
//! Compact logs are placed in a linker section named "log_fmt". This is a symbol exposed by the
21+
//! linker which points to the start of the section
22+
extern uint32_t __start_log_fmt;
23+
24+
//! Note: We don't read this in the firmware but it is used during the decode
25+
//! process to sanity check the section is being laid out as we would expect.
26+
MEMFAULT_PUT_IN_SECTION(".log_fmt_hdr")
27+
const sMemfaultLogFmtElfSectionHeader g_memfault_log_fmt_elf_section_hdr = {
28+
.magic = 0x66474f4c, /* LOGf */
29+
.version = 1,
30+
};
31+
32+
bool memfault_vlog_compact_serialize(sMemfaultCborEncoder *encoder, uint32_t log_id,
33+
uint32_t compressed_fmt, va_list args) {
34+
const uint32_t bits_per_arg = 2;
35+
const uint32_t bits_per_arg_mask = (1 << bits_per_arg) - 1;
36+
37+
const size_t num_args = (31UL - MEMFAULT_CLZ(compressed_fmt)) / bits_per_arg;
38+
39+
if (!memfault_cbor_encode_array_begin(encoder, 1 /* log_id */ + num_args)) {
40+
return false;
41+
}
42+
43+
// We use an offset within the section to reduce the space needed when serializing
44+
// the log.
45+
uint32_t log_fmt_offset = log_id - (uint32_t)(uintptr_t)&__start_log_fmt;
46+
47+
if (!memfault_cbor_encode_unsigned_integer(encoder, log_fmt_offset)) {
48+
return false;
49+
}
50+
51+
for (size_t i = 0; i < num_args; i++) {
52+
// See memfault/core/compact_log_helpers.h for more details. In essence,
53+
// the promotion type of a given va_arg is encoded within two bits of the
54+
// compressed_fmt field.
55+
const uint32_t type =
56+
(compressed_fmt >> ((num_args - i - 1) * bits_per_arg)) & bits_per_arg_mask;
57+
58+
bool success = false;
59+
switch (type) {
60+
61+
case MEMFAULT_LOG_ARG_PROMOTED_TO_INT32: {
62+
int32_t val = va_arg(args, int32_t);
63+
success = memfault_cbor_encode_signed_integer(encoder, val);
64+
break;
65+
}
66+
67+
case MEMFAULT_LOG_ARG_PROMOTED_TO_INT64: {
68+
// We differentiate between an 64 bit and 32 bit integer arg
69+
// by packing the cbor encoded int in an array.
70+
uint64_t val = va_arg(args, uint64_t);
71+
success = memfault_cbor_encode_array_begin(encoder, 1) &&
72+
memfault_cbor_encode_long_signed_integer(encoder, (int64_t)val);
73+
break;
74+
}
75+
76+
case MEMFAULT_LOG_ARG_PROMOTED_TO_DOUBLE: {
77+
// Note: Per the ARM ABI, doubles are just serialized out onto the stack
78+
// and occupy 8 bytes:
79+
//
80+
// Chapter 7: THE STANDARD VARIANTS
81+
// For a variadic function the base standard is always used both for argument passing and
82+
// result return.
83+
//
84+
// 6.5 Parameter Passing
85+
// In the base standard there are no arguments that are candidates for a co-processor
86+
// register class.
87+
//
88+
// So for ARM we could just do the following:
89+
// uint64_t val = va_arg(args, uint64_t)
90+
//
91+
// But parsing as a double is more portable and get's optimized away by compilers
92+
// like GCC anyway: https://godbolt.org/z/mVAS7D
93+
MEMFAULT_STATIC_ASSERT(sizeof(uint64_t) == sizeof(double), "double does not fit in uint64_t");
94+
95+
// Note: We use memcpy to properly type-pun / avoid strict-aliasing violation:
96+
// https://mflt.io/strict-aliasing-type-punning
97+
double val = va_arg(args, double);
98+
uint64_t double_as_uint64;
99+
memcpy(&double_as_uint64, &val, sizeof(val));
100+
success = memfault_cbor_encode_uint64_as_double(encoder, double_as_uint64);
101+
break;
102+
}
103+
104+
case MEMFAULT_LOG_ARG_PROMOTED_TO_STR: {
105+
const char *str = va_arg(args, const char*);
106+
success = memfault_cbor_encode_string(encoder, str != NULL ? str : "(null)");
107+
break;
108+
}
109+
110+
default:
111+
break;
112+
113+
}
114+
115+
if (!success) {
116+
return false;
117+
}
118+
}
119+
120+
return true;
121+
}
122+
123+
bool memfault_log_compact_serialize(sMemfaultCborEncoder *encoder, uint32_t log_id,
124+
uint32_t compressed_fmt, ...) {
125+
va_list args;
126+
va_start(args, compressed_fmt);
127+
const bool success = memfault_vlog_compact_serialize(encoder, log_id, compressed_fmt, args);
128+
va_end(args);
129+
130+
return success;
131+
}
132+
133+
#endif /* MEMFAULT_COMPACT_LOG_ENABLE */

components/core/src/memfault_trace_event.c

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@
33
//! Copyright (c) Memfault, Inc.
44
//! See License.txt for details
55

6-
#include "memfault/core/trace_event.h"
7-
#include "memfault_trace_event_private.h"
8-
96
#include <stdarg.h>
107
#include <stdbool.h>
118
#include <stdint.h>
@@ -14,12 +11,15 @@
1411

1512
#include "memfault/config.h"
1613
#include "memfault/core/arch.h"
14+
#include "memfault/core/compact_log_serializer.h"
1715
#include "memfault/core/debug_log.h"
1816
#include "memfault/core/event_storage.h"
1917
#include "memfault/core/event_storage_implementation.h"
2018
#include "memfault/core/math.h"
2119
#include "memfault/core/serializer_helper.h"
2220
#include "memfault/core/serializer_key_ids.h"
21+
#include "memfault/core/trace_event.h"
22+
#include "memfault_trace_event_private.h"
2323

2424
#define MEMFAULT_TRACE_EVENT_STORAGE_UNINITIALIZED (-1)
2525
#define MEMFAULT_TRACE_EVENT_STORAGE_OUT_OF_SPACE (-2)
@@ -94,8 +94,13 @@ static bool prv_encode_cb(sMemfaultCborEncoder *encoder, void *ctx) {
9494
}
9595

9696
if (success && log_present) {
97+
#if !MEMFAULT_COMPACT_LOG_ENABLE
9798
success = memfault_serializer_helper_encode_byte_string_kv_pair(encoder,
9899
kMemfaultTraceInfoEventKey_Log, info->log, info->log_len);
100+
#else
101+
success = memfault_cbor_encode_unsigned_integer(encoder, kMemfaultTraceInfoEventKey_CompactLog) &&
102+
memfault_cbor_join(encoder, info->log, info->log_len);
103+
#endif
99104
}
100105

101106
return success;
@@ -205,6 +210,8 @@ int memfault_trace_event_with_status_capture(eMfltTraceReasonUser reason, void *
205210
return prv_capture_trace_event_info(&event_info);
206211
}
207212

213+
#if !MEMFAULT_COMPACT_LOG_ENABLE
214+
208215
int memfault_trace_event_with_log_capture(
209216
eMfltTraceReasonUser reason, void *pc_addr, void *lr_addr, const char *fmt, ...) {
210217

@@ -236,6 +243,49 @@ int memfault_trace_event_with_log_capture(
236243
return prv_capture_trace_event_info(&event_info);
237244
}
238245

246+
#else
247+
248+
static void prv_fill_compact_log_cb(void *ctx, uint32_t offset, const void *buf, size_t buf_len) {
249+
uint8_t *log = (uint8_t *)ctx;
250+
memcpy(&log[offset], buf, buf_len);
251+
}
252+
253+
int memfault_trace_event_with_compact_log_capture(
254+
eMfltTraceReasonUser reason, void *lr_addr,
255+
uint32_t log_id, uint32_t compressed_fmt, ...) {
256+
257+
#if !MEMFAULT_TRACE_EVENT_WITH_LOG_FROM_ISR_ENABLED
258+
// If a log capture takes place while in an ISR we just record a normal trace event
259+
if (memfault_arch_is_inside_isr()) {
260+
return memfault_trace_event_capture(reason, 0, lr_addr);
261+
}
262+
#endif /* !MEMFAULT_TRACE_EVENT_WITH_LOG_FROM_ISR_ENABLED */
263+
264+
va_list args;
265+
va_start(args, compressed_fmt);
266+
uint8_t log[MEMFAULT_TRACE_EVENT_MAX_LOG_LEN] = { 0 };
267+
268+
sMemfaultCborEncoder encoder;
269+
memfault_cbor_encoder_init(&encoder, prv_fill_compact_log_cb, log, sizeof(log));
270+
memfault_vlog_compact_serialize(&encoder, log_id, compressed_fmt, args);
271+
size_t log_len = memfault_cbor_encoder_deinit(&encoder);
272+
273+
sMemfaultTraceEventInfo event_info = {
274+
.reason = reason,
275+
// Note: pc is recovered from file/line encoded in compact log so no need to collect!
276+
.pc_addr = 0,
277+
.return_addr = lr_addr,
278+
.opt_fields = TRACE_EVENT_OPT_FIELD_LOG_MASK,
279+
.log = &log[0],
280+
.log_len = log_len,
281+
};
282+
va_end(args);
283+
284+
return prv_capture_trace_event_info(&event_info);
285+
}
286+
287+
#endif
288+
239289
size_t memfault_trace_event_compute_worst_case_storage_size(void) {
240290
sMemfaultTraceEventInfo event_info = {
241291
.reason = kMfltTraceReasonUser_NumReasons,

components/demo/src/memfault_demo_cli_trace_event.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,9 @@
1313
#include "memfault/core/debug_log.h"
1414
#include "memfault/core/trace_event.h"
1515

16-
int memfault_demo_cli_cmd_trace_event_capture(MEMFAULT_UNUSED int argc,
17-
MEMFAULT_UNUSED char *argv[]) {
16+
int memfault_demo_cli_cmd_trace_event_capture(int argc, MEMFAULT_UNUSED char *argv[]) {
1817
// For more information on user-defined error reasons, see
1918
// the MEMFAULT_TRACE_REASON_DEFINE macro in trace_reason_user.h .
20-
MEMFAULT_TRACE_EVENT(MemfaultCli_Test);
19+
MEMFAULT_TRACE_EVENT_WITH_LOG(MemfaultCli_Test, "Example Trace Event. Num Args %d", argc);
2120
return 0;
2221
}

components/demo/src/panics/memfault_demo_panics.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ int memfault_demo_cli_cmd_crash(int argc, char *argv[]) {
8080
break;
8181

8282
case 4:
83-
MEMFAULT_SOFTWARE_WATCHDOG(0);
83+
MEMFAULT_SOFTWARE_WATCHDOG();
8484
break;
8585

8686
default:
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#pragma once
2+
3+
//! @file
4+
//!
5+
//! Copyright (c) Memfault, Inc.
6+
//! See License.txt for details
7+
//!
8+
//! @brief
9+
//!
10+
//! Compile time validity checks run on compact logs:
11+
//! 1) Enables printf() style Wformat checking
12+
//! 2) Verifies that number of args passed is <= the maximum number supported (15)
13+
14+
#include "memfault/config.h"
15+
16+
#ifdef __cplusplus
17+
extern "C" {
18+
#endif
19+
20+
#include <stdbool.h>
21+
22+
#if MEMFAULT_COMPACT_LOG_ENABLE
23+
24+
#include "memfault/core/compiler.h"
25+
#include "memfault/core/preprocessor.h"
26+
27+
#define MEMFAULT_LOGGING_MAX_SUPPORTED_ARGS 15
28+
29+
30+
static void _run_printf_like_func_check(const char* format, ...)
31+
MEMFAULT_PRINTF_LIKE_FUNC(1, 2);
32+
33+
//! Mark the function as used to prevent warnings in situations where this header is included but
34+
//! no logging is actually used
35+
MEMFAULT_USED
36+
static void _run_printf_like_func_check(MEMFAULT_UNUSED const char* format, ...) { }
37+
38+
//! Compilation time checks on log formatter
39+
//!
40+
//! - static asserts that argument list does not exceed allowed length.
41+
//! - Runs printf() style format checking (behind a "if (false)" so that
42+
//! the actual code gets optimized away)
43+
#define MEMFAULT_LOGGING_RUN_COMPILE_TIME_CHECKS(format, ...) \
44+
do { \
45+
MEMFAULT_STATIC_ASSERT( \
46+
MEMFAULT_ARG_COUNT_UP_TO_32(__VA_ARGS__) <= MEMFAULT_LOGGING_MAX_SUPPORTED_ARGS , \
47+
MEMFAULT_EXPAND_AND_QUOTE(MEMFAULT_ARG_COUNT_UP_TO_32(__VA_ARGS__)) \
48+
" args > MEMFAULT_LOGGING_MAX_SUPPORTED_ARGS (" \
49+
MEMFAULT_EXPAND_AND_QUOTE(MEMFAULT_LOGGING_MAX_SUPPORTED_ARGS) ")!"); \
50+
if (false) { \
51+
_run_printf_like_func_check(format, ## __VA_ARGS__); \
52+
} \
53+
} while (0)
54+
55+
#endif /* MEMFAULT_COMPACT_LOG_ENABLE */
56+
57+
#ifdef __cplusplus
58+
}
59+
#endif

0 commit comments

Comments
 (0)